Positions fixed doesn't work when using -webkit-transform

HtmlCssPositioningRotation

Html Problem Overview


I am using -webkit-transform (and -moz-transform / -o-transform) to rotate a div. Also have position fixed added so the div scrols down with the user.

In Firefox it works fine, but in webkit based browsers it's broken. After using the -webkit-transform, the position fixed doesn't work anymore! How is that possible?

Html Solutions


Solution 1 - Html

The CSS Transforms spec explains this behavior. Elements with transforms act as a containing block for fixed position descendants, so position:fixed under something with a transform no longer has fixed behavior.

They do work when applied to the same element; the element will be positioned as fixed, and then transformed.

Solution 2 - Html

After some research, there has been a bug report on the Chromium website about this issue, so far Webkit browsers can't render these two effects together at the same time.

I would suggest adding some Webkit only CSS into your stylesheet and making the transformed div an image and using it as the background.

@media screen and (-webkit-min-device-pixel-ratio:0) {
  /* Webkit-specific CSS here (Chrome and Safari) */
    
  #transformed_div {
    /* styles here, background image etc */
  }
}

So for now you'll have to do it the old fashioned way, until Webkit browsers catch up to FF.

EDIT: As of 10/24/2012 the bug has not been resolved.


This appears to not be a bug, but an aspect of the specification due to the two effects requiring separate coordinate systems and stacking orders. As explained in this answer.

Solution 3 - Html

Something (a bit hacky) that worked for me is to position:sticky instead:

.fixed {
     position: sticky;
}

Solution 4 - Html

For anyone who finds their background images are disappearing in Chrome because of the same issue with background-attachment: fixed; - this was my solution:

// run js if Chrome is being used
if(navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
	// set background-attachment back to the default of 'scroll'
	$('.imagebg').css('background-attachment', 'scroll');

 	// move the background-position according to the div's y position
	$(window).scroll(function(){
				
		scrollTop = $(window).scrollTop();
		photoTop = $('.imagebg').offset().top;
		distance = (photoTop - scrollTop);
		$('.imagebg').css('background-position', 'center ' + (distance*-1) + 'px');
				
	});
}  

Solution 5 - Html

August 2016 and fixed position & animation / transform is still a problem. The only solution that worked for me – was to create an animation for the child element that takes longer time.

Solution 6 - Html

Actually I found another way to fix this "bug":

I have container element which hold page with css3 animations. When the page completed the animation, the css3 property has value: transform: translate(0,0);. So, I just removed this line, and everything worked as it should - position: fixed is displayed properly. When css class is applied to translate the page, translate property is added and css3 animation worked as well.

Example:

.page {
     top: 50px;
     position: absolute;
     transition: ease 0.6s all;
     /* -webkit-transform: translate(0, 0); */
     /* transform: translate(0,0); */
 }
 .page.hide {
     -webkit-transform: translate(100%, 0);
     transform: translate(-100%, 0);    
 }

Demo: http://jsfiddle.net/ZWcD9/

Solution 7 - Html

I had this issue whilst trying to implement react-color with react-swipeable-views (rsw). The problem for me was that rsw applies translate(-100%, 0) to a tab panel which breaks the default fixed position div added over the full screen which when clicked closes the color picker model.

For me the solution was to apply the opposite transform to the fixed element (in this case translate(100%, 0) which fixed my issue. I'm not sure if this is useful in other cases but thought I would share anyway.

Here is an example showing what I've described above:

https://codepen.io/relativemc/pen/VwweEez

Solution 8 - Html

on my phonegap project the webkit transform -webkit-transform: translateZ(0); worked like a charm. It was already working in chrome and safari just not the mobile browser. also there can be one more issue is WRAPPER DIVs are not completed in some cases. we apply clear class in case of floating DIVs.

<div class="Clear"></div> .Clear, .Clearfix{clear:both;}

Solution 9 - Html

Probably due to a bug in Chrome as I can't replicate in Safari nor Firefox, but this works in Chrome 40.0.2214.111 http://jsbin.com/hacame/1/edit?html,css,output

It's a very particular structure so it's by no means a universally applicable one-lined css fix, but perhaps someone can tinker with it to get it working in Safari and Firefox.

Solution 10 - Html

Adding the -webkit-transform to the fixed element solved the issue for me.

.fixed_element {
   -webkit-transform: translateZ(0);
   position: fixed;
   ....
} 

Solution 11 - Html

Here is what works for me on all tested browsers and mobile devices (Chrome, IE, Firefox, Safari, iPad, iphone 5 and 6, Android).

img.ui-li-thumb {
    position: absolute;
    left: 1px;
    top: 50%;

    -ms-transform: translateY(-50%);
    -webkit-transform: translateY(-50%);
    -moz-transform: translateY(-50%);
    -o-transform: translateY(-50%);
    transform: translateY(-50%);
}

Solution 12 - Html

> the fixed position of an element is broken if you apply transform to any ancestor.

<div style='position:fixed;-.*-transform:scale(2)'>...</div> //ok
 
<div style='-.*-transform:scale(2)'>
      <div style='position:fixed'>...</div> // broken
</div>

Solution 13 - Html

If you can use javascript as an option this can be a workaround for positioning a position fixed element relavtive to the window when it's inside a transformed element:

  let fixedEl // some node that you is position 
              // fixed inside of an element that has a transform
  
  const rect = fixedEl.getBoundingClientRect()
  const distanceFromWindowTop = rect.top
  const distanceFromWindwoLeft = rect.left
  let top = fixedEl.offsetTop
  let left = fixedEl.offsetLeft

  if(distanceFromWindowTop !== relativeTop) {
    top = -distanceFromWindowTop
    fixedEl.style.top = `${top}px`
  }

  if(distanceFromWindowLeft !== relativeLeft) {
    left = -distanceFromWindowLeft
    fixedEl.style.left = `${left}px`
  }

Granted you will also have to adjust your heights and width because fixedEl will be calculating it's with based on it's container. That depends on your use case but this will allow you to predictably set the something position fixed, regardless of it's container.

Solution 14 - Html

Add a dynamic class while the element transforms.$('#elementId').addClass('transformed'). Then go on to declare in css,

.translatX(@x) { 
     -webkit-transform: translateX(@X); 
             transform: translateX(@x);
      //All other subsidaries as -moz-transform, -o-transform and -ms-transform 
}

then

#elementId { 
      -webkit-transform: none; 
              transform: none;
}

then

.transformed {
    #elementId { 
        .translateX(@neededValue);
    }
}

Now position: fixed when provided with a top and z-index property values on a child element just work fine and stay fixed until the parent element transforms. When the transformation is reverted the child element pops as fixed again. This should easen the situation if you are actually using a navigation sidebar that toggles open and closes upon a click, and you have a tab-set which should stay sticky as you scroll down the page.

Solution 15 - Html

in my case I found out we can't use transform: translateX() before transform:translateY().if we want to use both we should use transform:translate( , ).

Solution 16 - Html

If you're animating back to the original position where all translates are 0, you can use this solution where you set transform: unset;:

  100% {
    opacity: 1;
    visibility: visible;
    /* Use unset to allow fixed elements instead of translate3d(0, 0, 0) */
    transform: unset;
  }

Solution 17 - Html

Please don't up vote, because this is not exact answer, but could help someone because it's fast way just to turn off the transformation. If you really don't need the transformation on the parent and you want your fixed position working again:

#element_with_transform {
  -webkit-transform: none;
  transform: none;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioniSenneView Question on Stackoverflow
Solution 1 - HtmlsmfrView Answer on Stackoverflow
Solution 2 - HtmlKyleView Answer on Stackoverflow
Solution 3 - HtmlyckartView Answer on Stackoverflow
Solution 4 - HtmlJayden LawsonView Answer on Stackoverflow
Solution 5 - HtmldefligraView Answer on Stackoverflow
Solution 6 - HtmllowselfesteemsucksView Answer on Stackoverflow
Solution 7 - HtmlmrmadhatView Answer on Stackoverflow
Solution 8 - HtmlabksharmaView Answer on Stackoverflow
Solution 9 - HtmlKerry JohnsonView Answer on Stackoverflow
Solution 10 - HtmlRonView Answer on Stackoverflow
Solution 11 - HtmlMurfView Answer on Stackoverflow
Solution 12 - HtmlbortunacView Answer on Stackoverflow
Solution 13 - HtmlAdrian AdkisonView Answer on Stackoverflow
Solution 14 - Htmlmr.GView Answer on Stackoverflow
Solution 15 - HtmlFahime FiroozpourView Answer on Stackoverflow
Solution 16 - HtmlChrillewoodzView Answer on Stackoverflow
Solution 17 - HtmlmakkasiView Answer on Stackoverflow