使用 -webkit-transform 时固定位置不起作用

发布于 2024-08-28 15:54:05 字数 182 浏览 7 评论 0原文

我正在使用 -webkit-transform (和 -moz-transform / -o-transform)来旋转 div。还添加了固定位置,以便 div 随用户向下滚动。

在 Firefox 中它工作正常,但在基于 webkit 的浏览器中它就坏了。使用-webkit-transform后,固定的位置不再起作用了!这怎么可能?

I am using -webkit-transform (and -moz-transform / -o-transform) to rotate a div. Also have position fixed added so the div scrolls 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(21

ㄟ。诗瑗 2024-09-04 15:54:06

如果对任何祖先应用变换,元素的固定位置就会被破坏。

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

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

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>
老旧海报 2024-09-04 15:54:06

如果您可以使用 javascript 作为选项,这可以是当固定元素位于转换元素内时相对于窗口定位位置固定元素的解决方法:

  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`
  }

当然,您还必须调整高度和宽度,因为 fixedEl将根据其容器来计算它。这取决于您的用例,但这将允许您可预测地设置固定的某些位置,无论它的容器如何。

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.

北斗星光 2024-09-04 15:54:06

在元素变换时添加动态类。$('#elementId').addClass('transformed')
然后继续在 css 中声明,

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

然后

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

现在

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

的位置:固定,当在子元素上提供 top 和 z-index 属性值时,它可以正常工作并保持固定,直到父元素转换​​。当转换恢复时,子元素再次以固定状态弹出。如果您实际上使用的是在单击时打开和关闭的导航侧边栏,并且您有一个选项卡集,当您向下滚动页面时,该选项卡集应该保持粘性,这应该可以缓解这种情况。

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.

梦冥 2024-09-04 15:54:06

就我而言,我发现我们不能在translate:translateY()之前使用transform:translateX()。如果我们想同时使用两者,我们应该使用translate:translate(,)。

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( , ).

听闻余生 2024-09-04 15:54:06

如果您要动画回到所有翻译均为 0 的原始位置,则可以使用设置 transform: unset; 的此解决方案:

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

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;
  }
偷得浮生 2024-09-04 15:54:06

如果你使用 React 那么你可以使用 ReactDOM.createPortal。

感谢 Porkopek 给我的小费,但我花了一些时间才弄清楚这东西是什么。
所以这就是我发现的:

如果你返回一个包装在 ReactDOM.createPortal 中的组件,那么你可以设置父元素作为第二个参数,React 会将组件附加到给定的元素,例如 position:fixed 即使作为转换后的组件的子组件也没有问题。

import ReactDOM from "react-dom";


const MyModal = () => {
    return ReactDOM.createPortal(
       <div style={{position: "fixed", top: "0", left: "0", 
                    background: "white", color: "black", 
                    padding: "3rem", zIndex: "50000"}}>
         Modal Element
       </div>,
       document.body
    )

}

在这种情况下,React 会将此组件渲染为主体的子组件,而不是父组件的子组件。

If you use React then you can use ReactDOM.createPortal.

Credit goes for Porkopek for the tip, but it took me some time to figure out what this thing is.
So here's what I found:

If you return a component wrapped in ReactDOM.createPortal then as the second argument you can set the parent element, and React will append the component to that given element, so example position: fixed will be fine even as a child of a transformed component.

import ReactDOM from "react-dom";


const MyModal = () => {
    return ReactDOM.createPortal(
       <div style={{position: "fixed", top: "0", left: "0", 
                    background: "white", color: "black", 
                    padding: "3rem", zIndex: "50000"}}>
         Modal Element
       </div>,
       document.body
    )

}

In this case React will render this component as the child of the body, not as the child of the parent component.

狠疯拽 2024-09-04 15:54:06

请不要投票,因为这不是确切的答案,但可以帮助某人,因为这是关闭转换的快速方法。
如果您确实不需要对父级进行转换并且希望您的固定位置再次工作:

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

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;
}
七婞 2024-09-04 15:54:05

CSS 转换规范 解释了这种行为。具有变换的元素充当固定位置后代的包含块,因此具有变换的元素下的position:fixed不再具有固定行为。

当它们应用于相同的元素时,它们确实起作用;该元素将被定位为固定,然后进行转换。

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.

后eg是否自 2024-09-04 15:54:05

经过一番研究后,错误报告出现在 < a href="http://code.google.com/chromium/" rel="noreferrer">Chromium 网站介绍了这个问题,到目前为止Webkit浏览器还不能同时渲染这两种效果。

我建议在样式表中添加一些仅 Webkit 的 CSS,并将转换后的 div 制作为图像并将其用作背景。

@media screen and (-webkit-min-device-pixel-ratio:0) {
  /* Webkit-specific CSS here (Chrome and Safari) */

  #transformed_div {
    /* styles here, background image etc */
  }
}

所以现在你必须用老式的方式来做,直到 Webkit 浏览器赶上 FF。

编辑:截至 2012 年 10 月 24 日,该错误尚未解决。


这似乎不是一个错误,而是规范的一个方面,因为两种效果需要单独的坐标系和堆叠顺序。 如本答案所述

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.

笔落惊风雨 2024-09-04 15:54:05

对我有用的东西(有点 hacky)是 position:sticky

.fixed {
     position: sticky;
}

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

.fixed {
     position: sticky;
}
摇划花蜜的午后 2024-09-04 15:54:05

对于那些发现自己的背景图像由于与背景附件相同的问题而在 Chrome 中消失的人:已修复; - 这是我的解决方案:

// 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');

    });
}  

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');

    });
}  
横笛休吹塞上声 2024-09-04 15:54:05

2016年8月并固定职位&动画/变换仍然是一个问题。对我有用的唯一解决方案是为需要更长时间的子元素创建动画。

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.

满身野味 2024-09-04 15:54:05

实际上我找到了另一种方法来修复这个“bug”:

我有一个容器元素,它保存带有 css3 动画的页面。当页面完成动画时,css3属性的值为:transform:translate(0,0);。所以,我刚刚删除了这一行,一切都按预期工作 -position:fixed 正确显示。当应用 css 类来翻译页面时,会添加 translate 属性,并且 css3 动画也可以工作。

示例:

.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);    
 }

演示:
http://jsfiddle.net/ZWcD9/

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/

天生の放荡 2024-09-04 15:54:05

在我的phonegap项目中,webkit转换-webkit-transform:translateZ(0);就像魅力一样。
它已经可以在 Chrome 和 Safari 中运行,但不能在移动浏览器中运行。
另外,还有一个问题是 WRAPPER DIV 在某些情况下未完成。我们在浮动 DIV 的情况下应用清晰的类。

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

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;}
迷雾森÷林ヴ 2024-09-04 15:54:05

我在尝试使用react-swipeable-views(rsw)实现react-color时遇到了这个问题。对我来说,问题是 rsw 将 translate(-100%, 0) 应用于选项卡面板,这会破坏在全屏上添加的默认固定位置 div,单击该选项卡会关闭颜色选择器模型。

对我来说,解决方案是将相反的变换应用于固定元素(在本例中 translate(100%, 0) 解决了我的问题。我不确定这在其他情况下是否有用,但我想无论如何都会分享。

这是一个显示我上面描述的内容的示例:

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

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

花开柳相依 2024-09-04 15:54:05

将固定元素设置为 transform:unset; 对我有用。

Setting fixed element to transform:unset; is working for me.

左秋 2024-09-04 15:54:05

如果你使用 React,你可以将元素包装在 Portal 中的固定位置,这样它就可以正常工作

If you work with React, you can wrap the element with fixed position in a Portal, and this way it will work fine

昵称有卵用 2024-09-04 15:54:05

-webkit-transform 添加到固定元素解决了我的问题。

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

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

.fixed_element {
   -webkit-transform: translateZ(0);
   position: fixed;
   ....
} 
许久 2024-09-04 15:54:05

可能是由于 Chrome 中的错误,因为我无法在 Safari 或 Firefox 中复制,但这适用于 Chrome 40.0.2214.111 http://jsbin.com/hacame/1/edit?html,css,output

这是一个非常特殊的结构,因此它绝不是一个普遍适用的单行 css 修复,但是也许有人可以修改它,让它在 Safari 和 Firefox 中工作。

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.

挽梦忆笙歌 2024-09-04 15:54:05

我刚刚将 transform: unset; 添加到我的固定标头中,这对我有用!

我还在 Next.js 中使用成帧器运动,并且我的固定标题也有同样的问题,这似乎很容易解决它。

.header {
    position: fixed;
    transform: unset;
}

I just added transform: unset; to my fixed header and that worked for me!

I am also using framer motion with Next.js and having the same problem with my fixed header and this seems to fix it easily.

.header {
    position: fixed;
    transform: unset;
}

旧瑾黎汐 2024-09-04 15:54:05

以下是在所有经过测试的浏览器和移动设备(Chrome、IE、Firefox、Safari、iPad、iphone 5 和 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%);
}

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%);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文