I have the following CSS applied to the <html> tag: filter: invert(1);
All elements get inverted even background-color of elements, (Chrome v80)
Once I try the same on Safari iOS 13 / Safari MacOS, every element get inverted except for <html>'s background-color
CSS filter property is supported for all browsers I'm running:
https://caniuse.com/#feat=mdn-css_properties_filter.
Could someone explain this behavior?
html {
  filter: invert(1);
  /* this background-color does not change on ios+other browsers */
  background: #fff;
  padding: 50px;
}
body {
  background-color: #0000ff;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
}
.text {
  text-align: center;
  color: red;
}
<div class="text">
  If it works: color should not be red, background should not be blue
</div>
html element.The easy workaround is to block body's background propagation to the document's canvas, but make it take the same size as the html by removing its margin, and applying all the styles you had on html on the body, and the ones you had on the body to a wrapper <div>.
html {
  /* block body's background propagation */
  background: #FFF;
}
/* move all one layer down */
body {
  filter: invert(1);
  background: #fff;
  padding: 50px;
  /* make it cover the full canvas */
  margin: 0;
}
.wrapper {
  background-color: #0000ff;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
}
.text {
  text-align: center;
  color: red;
}
<div class="wrapper">
  <div class="text">
    If it works: color should not be red, background should not be blue and border should not be white
  </div>
</div>
There are a few concepts at play here, and their interaction is not that easy to grasp (at least to me...).
"Background propagation": Some special elements have special behaviors regarding their CSS background property. Notably, html and body may give their own background to the "document's canvas". The basic workflow is  
html's background is not none and not transparent, use that for "document's canvas".body's background is not none and not transparent, use that for "document's canvas"."Post-Processing" effects like filter and opacity should apply on a whole "rendering layer" when all its inner content already has been rendered.  
Now, it's very unclear how the "document's canvas" should be affected by these "post-processing" effects, and I couldn't find any definitive answer to this case in the specs.
What's for sure, is that we have [Compat] issues in there...
Not only not all browsers do follow the same rules, but some browsers will behave differently when the page is presented as a standalone window, or in an iframe.
Since the test results do vary between windowed and framed renderings, and that StackSnippet only allows framed rendering, I am forced to outsource the test case in this plnkr.
html {
  background: red;
  height: 50vh;
  border: 10px solid green;
}
.opacity {
  opacity: 0.5;
}
.filter {
  filter: invert(1);
}
body {
  background: yellow;
  margin: 10vh;
  border: 2px solid green;
}
The results from these tests for majors browsers are:
When windowed: (screenshot orders, from left to right: nothing, filter, opacity, filter + opacity).
<html> when opacity is set and applies both opacity and filter on the <html>'s background.<body>'s background color as the document's canvas... but let it unaffected by the filter.
        
      When framed: (screenshot orders, from left to right: nothing, filter, opacity, filter + opacity).
<html> on which the opacity is applied.<html> when opacity is set and applies both opacity and filter on the <html>'s background.
        
      So once again, I don't know if any result here is per specs, what I know is that as web-authors, we should avoid messing with it when possible.
Post-scriptum:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With