Please note if you want to enable high contrast mode from the browser, you can't. This answer is how to apply your High Contrast Styles via a button click while maintaining the media query that doesn't rely on JavaScript to work.
This solution allows you to keep the styles for IE as a media query but also allow them to be toggled manually. It does depend on your high contrast CSS to be located in a separate external file.
What we do is add the style sheet that contains your high contrast CSS rules as an external file.
We give this file a unique ID (#doNotChangeMe
) and the relevant media query media="screen and (-ms-high-contrast: active)"
.
As the above file will only work for IE we are safe to leave it alone.
We then create a function that can also add and remove this style sheet on a button click.
I created a simple toggle function that will query to see if the style sheet exists (without the #doNotChangeMe
id) using a CSS selector.
'link[href*="' + externalFileName + '"]:not(#doNotChangeMe)'
(look for a link with the href
we provided, as long as it doesn't have the relevant ID).
We then see if this CSS file exists in the DOM, if it doesn't we add it again (which will cause no harm assuming your high contrast CSS is the last style sheet in the DOM), otherwise we remove it.
I did try to make this cleaner by changing the media query programatically, however this seemed to have mixed results in browsers and the above seems to work consistently (CORS security policy kicks in if you try to change media.mediaText
for example).
I have linked to the Bootstrap style sheet in the example just for ease of demonstration. You will have to inspect the DOM to see that the high contrast style sheet is not touched by this function (or enable high contrast mode in IE to see that the toggle does not affect anything).
Please note I have not added any indicators to the toggle button to show whether the mode is active, make sure you add relevant WAI-ARIA, button text etc.
//Please note that the below assumes you do not want to interfere with normal media query, if you want people who do have high contrast mode enabled you will need to modify this to remove the ignoreIdOrClass part and instead have a variable containing the state.
var ignoreIdOrClass = '#doNotChangeMe'; //this is the ID of the file that was already in the DOM we do not want to touch
var externalFileName = document.querySelector(ignoreIdOrClass).href; //we grab the URL of the file we want to replicate
function toggleHighContrast() {
var linkNode = document.querySelector('link[href*="' + externalFileName + '"]:not(' + ignoreIdOrClass + ')'); //see if we have added this style sheet to the DOM ourselves, ignore the one with the ID we said to ignore
if(!linkNode){ //our css file copy doesn't exist so create it and add it to the document HEAD
var head = document.head;
var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
link.href = externalFileName;
head.appendChild(link);
}else{ //our css copy does exist so remove it
linkNode.parentNode.removeChild(linkNode);
}
}
document.getElementById("myBtn").addEventListener("click", toggleHighContrast);
<link id="doNotChangeMe" rel="stylesheet" media="screen and (-ms-high-contrast: active)" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" />
<div style="padding: 20px;">
<button id="myBtn" class="btn btn-primary btn-lg">Toggle High Contrast</button>
</div>