【问题标题】:Incremental CSS Media Queries增量 CSS 媒体查询
【发布时间】:2019-08-05 08:14:13
【问题描述】:

考虑使用media 查询和transform 来调整页面大小的样式表:

@media (max-height: 620px) {
    body {
    transform: scale(0.95);
    }
}
@media (max-height: 590px) {
    body {
    transform: scale(0.90);
    }
}
@media (max-height: 560px) {
    body {
    transform: scale(0.85);
    }
}
// and so on ...

随着窗口高度的减小,页面会“缩小”,从而可以在较小的屏幕上显示全部内容。 如果我想支持小于560px 高度的屏幕,我需要添加更多media 查询。

请注意,对于每一个在高度上损失的30px,我们在输入中调用带有0.05 less 的比例。

问题:有没有办法只使用css来定义增量媒体查询?

跟进:如果没有纯css解决方案,那么在vanilla JS中实现这种效果的最简单方法是什么?

编辑:感谢大家针对此问题发布不同的解决方案。我感谢您的帮助。您的回答帮助我学习了如何改进我的代码。

【问题讨论】:

  • 在Vanilla JS中(window.innerHeight) / (document.body.clientHeight)是你需要的比例。
  • 我认为您可以为此使用像 sass 这样的 css 预处理器
  • 缩放后的文字看起来很模糊。您可以更好地使用vwvh 单位进行布局吗?

标签: javascript html css css-transforms


【解决方案1】:

仅使用 CSS 是不可能的。您可以通过添加一个 window.onresize 函数来使用 JS 来执行此操作,以观察调整和缩放documentbody。此解决方案还可以动态扩展,因此您无需担心断点或@media 查询。

function updateScale() {
  let viewScale = window.innerHeight / document.documentElement.scrollHeight;
  document.body.style = 'transform:scale(' + viewScale + ')';
  document.documentElement.scrollHeight = window.innerHeight;
}

window.onresize = function() {
  updateScale();
}
updateScale();
body {
  transform-origin: 0 0;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

#block {
  background-color: black;
  width: 300px;
  height: 4000px;
}
<div id='block'></div>

【讨论】:

    【解决方案2】:

    @NathanFries 是正确的,这不是原生 CSS 所能实现的。

    CSS 包含 viewport units 用于您的宽度和高度的基于百分比的值,但您不能将其传递给 scale() 函数。

    然后您需要将其绑定到某个 resize 事件侦听器。

    这里有一个简单的例子,可以完成你想做的事情:

    // @see https://github.com/WICG/EventListenerOptions/blob/9dcca95/explainer.md#feature-detection
    // @example `elem.addEventListener('touchstart', fn, supportsPassive ? { passive: true } : false);`
    var checkSupportPassiveEvents = function() {
        var supportsPassive = false;
        try {
            var opts = Object.defineProperty({}, 'passive', {
                get: function() {
                    supportsPassive = true;
                },
            });
            window.addEventListener('testPassive', null, opts);
            window.removeEventListener('testPassive', null, opts);
        } catch (e) {}
    
        return supportsPassive;
    };
    
    var supportsPassive = checkSupportPassiveEvents();
    
    var mapRange = function(fn, inStart, inEnd, outStart, outEnd) {
        if (outStart === void 0) {
            outStart = inStart;
            outEnd = inEnd;
            inStart = 0;
            inEnd = 1;
        }
    
        var inRange = inEnd - inStart,
            outRange = outEnd - outStart;
    
        return function(val) {
            var original = fn((val - inStart) / inRange);
            return outStart + outRange * original;
        };
    };
    
    var linear = function(x) {
        return x;
    };
    
    var minHeight = 320;
    var maxHeight = 620;
    var minScale = 0.45;
    var maxScale = 1;
    var screenHeightToScaleFactorInner = mapRange(linear, minHeight, maxHeight, minScale, maxScale);
    
    var screenHeightToScaleFactor = function(height) {
        if (height <= minHeight) {
            return minScale;
        } else if (height > maxHeight) {
            return maxScale;
        } else {
            return screenHeightToScaleFactorInner(height);
        }
    };
    
    window.addEventListener(
        'resize',
        function(e) {
            var height = this.innerHeight;
    
            this.document.body.style.transform = 'scale(' + screenHeightToScaleFactor(height) + ')';
        },
        supportsPassive ? { passive: true } : false
    );
    

    【讨论】:

      【解决方案3】:

      在这种情况下,您可能必须使用vanilla JavaScript

      所以,每个30px0.05,或者每个6px0.01650px 向下。

      这意味着600px的数量是1,每个pixel0.01/6

      考虑到所有这些信息,我们可以使用resize 事件来计算:

      window.addEventListener('resize', changeTransform); // when resize, call changeTransform
      
      var bodyEl = document.querySelector('body');
      
      function changeTransform() {
      
        var scale = 1; // default scale
        if (window.innerHeight < 650) { // if window height < 650px, do magic
          scale = -0.83 + (0.05/30)*window.innerHeight;
        }
        bodyEl.style.transform = "scale(" + scale + ")"; // apply scale (1 or the calculated one)
      
      }
      

      希望它能以某种方式帮助你。

      【讨论】:

      • 您的回答直截了当,直面问题。我只会对比例进行轻微修改,并将其设置为scale = -0.83 + (0.05/30)*window.innerHeight。这实现了在scale 中减少0.05 中的每一个30px 的高度损失。
      • 很高兴它对您有所帮助。是的,我明白了。已编辑。
      【解决方案4】:

      对于 CSS 解决方案,您可以考虑使用 vhvw 单位,但无法使用规模,因为这需要一个无单位的值。

      另一种方法是使用translateZ() 和一些透视来模拟缩放动画。

      这是一个基本示例。结果不准确,因为我只是想演示这个技巧。运行sn -p整页调整窗口高度,就可以看到元素缩放了。

      .box {
        width:100px;
        height:100px;
        background:red;
        transform:perspective(180px) translateZ(15vh);
        transform-origin:top left;
      }
      <div class="box">
      some text here
      </div>

      您只需要为不同的值找到正确的计算方法。

      【讨论】:

      • 我不认为这表明这会奏效。事实上,我认为它起作用。我一直在尝试使用 translateZ 提出解决方案,但没有成功。我认为如果您的视角为 180px 并且不希望在窗口高度为 650px 时进行缩放,您将需要类似 translateZ(calc(180px * (100vh / 650px) - 180px)) 的东西。但是,“/”运算的除数中只能使用数字。长度无效。此外,* 操作中的至少一个参数必须是长度,所以对我来说这似乎是不可能的。
      • @MarkFisher 我只是在演示技巧。我从来没有说过它会起作用。顺便说一句,如果高度小于 650 像素,我们可以结合更多翻译并考虑嵌套元素,还可以添加一个媒体查询来激活/描述翻译。由于没有简单的 CSS 解决方案,我试图找到仅使用 CSS 的近似值。
      • 当你说“你只需要为不同的值找到正确的计算。”这向我暗示,如果您将适当的值插入到 translateZ(),您认为它会起作用。
      猜你喜欢
      • 2022-01-25
      • 2021-08-23
      • 2012-02-15
      • 2019-12-09
      • 1970-01-01
      • 1970-01-01
      • 2012-10-15
      • 2017-01-06
      相关资源
      最近更新 更多