4

Demo page

body {
  -webkit-filter: blur(2px);
  filter: blur(2px);
}

div {
  background: blue;
  margin: auto;
  position: absolute;
  right: 0;
  top: 50%;  /*  <---- ignored */
  left: 0;
  height: 200px;
  width: 200px;
  transform: translateY(-50%);
}
<div></div>

Giving filter:blur(1px) (or any other filter) to a parent of a positioned element makes the browser ignore the child's position.

Has anyone encountered that and know a way to fix this annoyance?


Tested on FF48 beta / win7

vsync
  • 118,978
  • 58
  • 307
  • 400
  • if we can give parent element height "height: 500px;".child position will work. – iyyappan Jun 21 '16 at 16:51
  • 1
    I have the [same issue](https://stackoverflow.com/questions/62717289/). I submitted a [bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1650522) to Firefox and I'm also asking the W3C to [change the spec](https://github.com/w3c/fxtf-drafts/issues/402) for filters that have nothing to do with size/position. – Lonnie Best Jul 04 '20 at 08:55

2 Answers2

8

That's because absolutely positioned elements are positioned relatively to their containing block, which is established by their nearest positioned ancestor, or the initial containing block if there is no such ancestor.

Then, if you don't use filter, the containing block will be the initial one, which has the same dimensions as the viewport.

However, if you use filter on body, that will establish a containing block, even for absolutely positioned descendants. It will be like if you used position: relative.

body {
  position: relative;
}
div {
  background: blue;
  margin: auto;
  position: absolute;
  right: 0;
  top: 50%;
  left: 0;
  height: 200px;
  width: 200px;
  transform: translateY(-50%);
}
<div></div>

Instead, I recommend setting the filter on html, and use height: 100% to make it as tall as the viewport.

html {
  height: 100%;
  -webkit-filter: blur(2px);
  filter: blur(2px);
}
div {
  background: blue;
  margin: auto;
  position: absolute;
  right: 0;
  top: 50%;
  left: 0;
  height: 200px;
  width: 200px;
  transform: translateY(-50%);
}
<div></div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • @vsync That was not the point of my answer. When I said "absolutely positioned", I included fixed. – Oriol Jun 21 '16 at 19:12
  • But positioned `fixed` elements do not care about relative parents. they are relative only to the window itself, so this is in fact seems like a browser bug no? – vsync Jul 26 '16 at 11:14
  • 1
    @vsync No. Relatively positioned elements establish a containing block for absolutely positioned descendants, but not for fixed ones. `filter` establishes a containing block for fixed ones too. So the behavior is somewhat analogous to a relatively positioned container and an absolutely positioned descendant. – Oriol Jul 26 '16 at 22:08
  • 2
    I wonder why is that? it seems like a spec decision which can screw up so much and there is no way to fix this – vsync Jul 27 '16 at 13:04
  • Because it's faster. For browsers it would be more expensive to make filter affect descendants whose containing block is established by an ancestor of the filtered element – Oriol Jul 27 '16 at 19:18
1

body{ 
  -webkit-filter:blur(2px); 
  filter:blur(2px); 
  /* setting the viewport height on body */
  min-height: 100vh;
}

div{
  background: blue;
  margin: auto;
  position: absolute;
  right: 0;
  top: 50%;
  left: 0;
  height:200px;
  width: 200px;
  transform: translateY(-50%);
}
<div></div>

Setting the body to min-height of viewport seems to work.

orangeh0g
  • 418
  • 2
  • 10
  • My demo was the most simple code and cannot be taken lightly since the actual code is much more complex. there is no body. there is no min-height that can be given. – vsync Jun 21 '16 at 19:07