CSS媒体查询问题(滚动条)

Posted

技术标签:

【中文标题】CSS媒体查询问题(滚动条)【英文标题】:issue with CSS media queries(scrollbar) 【发布时间】:2011-12-30 02:51:05 【问题描述】:

我在 Firefox 中遇到 css 媒体查询问题。它在 Chrome 中可以正常工作,就像我制作了两个 DIV 并想要一个滚动条一样。如果我将 firefox 的屏幕尺寸减小到 800 像素,那么两个 DIV 都会崩溃,并且在一些像素媒体查询工作之后,但在 Chrome 中不会发生这种情况。

检查这个小提琴http://jsfiddle.net/RMvqC/2/

【问题讨论】:

+1 我也面临同样的问题 我会因为像@media all and (max-width: calc(980px + scrollbar-width))这样的媒体查询而杀人 【参考方案1】:

我通过在我的项目头部调用“mqGenie”javascript 解决了这个问题。

现在,我的媒体查询的宽度在 Chrome、Safari、Firefox 和 IE 上都可以正常工作(具有相同的值),无论是否带有滚动条。

此 javascript 调整浏览器中的 CSS 媒体查询,包括视口宽度中的滚动条宽度,以便它们以预期大小触发。

你可以从这个网址下载:

http://stowball.github.io/mqGenie/

【讨论】:

这似乎是真正的解决方案,因为我讨厌在我的项目中添加更多的 javascript 来适应错误的浏览器行为。至少它是非常轻量级的时钟,小于 1.2KB。我实际上可能会将这个源代码直接嵌入到我的页面中。 我觉得用这个很脏,但它似乎是解决我问题的唯一方法。 这正是媒体查询应该做的。感谢您解决了一个非常令人沮丧的错误。【参考方案2】:

基于 Firefox 和 Webkit 的浏览器以不同的方式呈现滚动条。在 Firefox 中,MediaQuery 考虑滚动条的宽度,即 15px 与屏幕宽度,但在基于 Webkit 的浏览器中,它不被视为具有屏幕宽度的滚动条。所以,这就是浮动 DIV 在 Firefox 中折叠的原因。

我用 css 做了一些东西可能对你有帮助。 (查看this fiddle)

        html 
            /* force scrollbars */
            height: 101%;
        
        body 
            margin: 0; 
            padding:0; 
            white-space:nowrap; 
          
        #box1,
        #box2 
            display:inline-block;
            width: 400px;
            height: 200px;  
            vertical-align:top;
            white-space:normal;
        
        #box1 
            background: #ce0000;
             margin-right:-5px;
        
        #box2 
            background: #8e0000;
        

        @media screen and (max-width: 799px)  
            body  
                white-space:normal; 
            
            #box1,
            #box2 
                width: 300px;
            
        

【讨论】:

好痛苦,这就是为什么我有时/大部分时间讨厌前端 我认为这在 Chrome 29 前后发生了变化。滚动条现在包含在关于媒体查询计算的页面宽度中 很遗憾现在是 2020 年,这仍然是一个问题。使媒体查询对于没有 hacky javascript 的微调内容毫无用处。 现在是 2021 年,看起来基于 webkit 的浏览器上的媒体查询已经开始考虑滚动条的宽度。如果我错了,请纠正我。【参考方案3】:

Firefox & Opera 遵循 W3C 规范,即在媒体查询宽度中包含滚动条宽度(原因可能是为了避免a comment here 中描述的无限循环),而 Webkit 没有(可能是因为他们认为这没有意义)

有一个解决方法(我只在 FF 上测试过),显然如果你强制滚动条一直可见,那么宽度现在将与 Webkit 保持一致。代码如下:

html

   overflow:hidden;
   height:100%;

body

   position:relative;
   overflow-y:scroll;
   height:100%;
   -webkit-overflow-scrolling:touch; /* So ios Safari gets the inertia & rubber-band effect */

如果您只想将此应用到 FF 和 Opera,您可以求助于 CSS hack:

/* Firefox */
@-moz-document url-prefix()

    html
    
        overflow:hidden;
        height:100%;
    
    body
    
        position:relative;
        overflow-y:scroll;
        height:100%;
        /*-webkit-overflow-scrolling:touch;*/
    


/* Opera */
x:-o-prefocus, html

    overflow:hidden;
    height:100%;

x:-o-prefocus, body

    position:relative;
    overflow-y:scroll;
    height:100%;

不用说,需要注意的是滚动条将始终可见,这可能是一个不错的折衷方案。

【讨论】:

【参考方案4】:

注意安全!

我的最终策略是在媒体查询中添加 20 像素,这是我在布局上的默认空白。

有一个例外:@media (min-width: 320px) 在那个尺寸下,不要留下 20 像素的空白区域,并添加一条规则来解决较小的背景问题:

html body 
    min-width: 320px;
   

20px 是滚动条默认宽度大小。

仅供参考:https://www.sitepoint.com/rwd-scrollbars-is-chrome-better/

【讨论】:

【参考方案5】:

您可以使用 CSS-hack 轻松实现 Firefox 解决方案。将您的内容包装在一个额外的 <div> 中后,将此行添加到您的 CSS:

/* Firefox-Hack */
body,  x:-moz-any-link 
    overflow-x: hidden;

#wrapper,  x:-moz-any-link 
    margin: 0 -7.5px;

检查jsbin(jsfiddle 现在已关闭)

要获得更丰富的响应体验,您可以添加另一个媒体查询:another jsbin

CSS-hack 发现于 paulirish.com

【讨论】:

【参考方案6】:

这是外围相关的,但我找到了一种方法来检测浏览器在任何给定时刻实际使用的媒体查询,而不必乱用滚动条和正文宽度......

基本上,在您的身体某处定义一个绝对定位的 1-x-1 像素大小的列表,其中包含您希望“可观看”的每个媒体查询条件的列表项。

然后在每个媒体查询定义中,显示/隐藏相应的列表项,然后简单地检查该项目在您的脚本中是否可见。

例子:

<body>
    ...
    <ul id="mediaQueryHelper">
        <li id="desktop"></li>
    </ul>
</body>

<style type="text/less">
    #mediaQueryHelper 
        position: absolute;
        height: 1px;
        width: 1px;
        visibility: hidden;
        top: -999px;
        left: -999px;
    

    @media screen and (min-width: 481px)
    
       #desktop  display: inline; 
    

    @media screen and (min-width: 320px) and (max-width: 480px)
    
       #desktop display: none; 
    

</style>

<script type="text/javascript">
    $(document).ready(function()
    
        var _desktop = $("#desktop");

        $(window).resize(function() 
            console.log("media-query mode: " + _desktop.is(":visible") ? "DESKTOP" : "MOBILE");
        );
    );
</script>

【讨论】:

【参考方案7】:

简答

如果您不想一直显示滚动条,请将您的内容包装到 &lt;div&gt; 元素等中。您可以使用 JavaScript 在显示滚动条时为所有媒体查询添加特定值。

// check whether scrollbar is visible
var isScrollbarVisible = window.innerWidth > document.documentElement.clientWidth;

// search for media rule
var mediaRule = document.styleSheets[i].cssRules[j];

// update media rule
mediaRule.media.mediaText = '..'

长答案

我编写了一个小脚本,您可以将其包含在您的页面中。它检测窗口何时调整大小并在需要时更改所有媒体查询。 css 变量--replace-media-scrollbar 的值用作滚动条的宽度,如果没有找到值,则使用15px。这适用于媒体查询withmin-widthmax-widthheightmin-heightmax-height,即使它们使用and 连接也是如此。

JavaScript:

function* visitCssRule(cssRule) 
    // visit imported stylesheet
    if (cssRule.type == cssRule.IMPORT_RULE)
        yield* visitStyleSheet(cssRule.styleSheet);

    // yield media rule
    if (cssRule.type == cssRule.MEDIA_RULE)
        yield cssRule;


function* visitStyleSheet(styleSheet) 
    try 
        // visit every rule in the stylesheet
        var cssRules = styleSheet.cssRules;
        for (var i = 0, cssRule; cssRule = cssRules[i]; i++)
            yield* visitCssRule(cssRule);
     catch (ignored) 


function* findAllMediaRules() 
    // visit all stylesheets
    var styleSheets = document.styleSheets;
    for (var i = 0, styleSheet; styleSheet = styleSheets[i]; i++)
        yield* visitStyleSheet(styleSheet);


// collect all media rules
const mediaRules = Array.from(findAllMediaRules());

// read scrollbar width
var style = getComputedStyle(document.documentElement);
var scrollbar = style.getPropertyValue('--replace-media-scrollbar') || '15px';

// update media rules
if (scrollbar != '0px') 
    var oldValue = '0px';
    function updateMediaRulesScrollbar() 
        var newValue = window.innerWidth > document.documentElement.clientWidth ? scrollbar : '0px';
        // if value changed
        if (oldValue != newValue) 
            for (var i = 0, mediaRule; mediaRule = mediaRules[i]; i++) 
                var regex = RegExp('\\((width|min-width|max-width|height|min-height|max-height): (calc\\([^)]*\\)|[^)]*)\\)', 'g');
                var replacement = '($1: calc($2 - ' + oldValue + ' + ' + newValue + '))';
                mediaRule.media.mediaText = mediaRule.media.mediaText.replace(regex, replacement);
                console.log(mediaRule);
            
        
        oldValue = newValue;
    
    updateMediaRulesScrollbar();
    window.onresize = updateMediaRulesScrollbar;

可选 CSS:

:root 
  --replace-media-scrollbar: 15px;

【讨论】:

以上是关于CSS媒体查询问题(滚动条)的主要内容,如果未能解决你的问题,请参考以下文章

CSS媒体查询和选择器[重复]

为啥我的简单媒体查询在模拟手机时会产生滚动条[重复]

带有纯 CSS3 媒体查询的 IE9 响应式图像调整大小问题

媒体查询断点忽略 html min-width [重复]

chrome 26.0.XXX版本下media query流媒体查询有问题的bug

IE 的 CSS 选择器限制中如何计算媒体查询?