CSS – vw, vh, position fixed and ICB (initial containing block)
什么是 vw, vh?
vh 的 v 指的是 viewport, h 就是 height. 它是 CSS 值的单位就像 px, %.
.container { height: 30vh; background-color: red; }
那么 30vh 是多高呢?
30% of viewport heigth 的意思.
vh 和 % 的区别
% 对标当前 element 的 parent (或更准确的说是 containing block) 来计算的.
而 vh 则对标 viewport (initial containing block ICB) 来计算的.
ICB (Initial Containing Block)
既然 vh 是 viewport 的 percentage, 那就要先搞清楚 viewport(更准确的叫法是 ICB) height 具体是多少.
viewport 一般上指的就是屏幕 avaiable size (可视区). 也就是扣除了 address bar, tool bar, bookmark bar 等等
但是有些东西却会影响 viewport 的 size, 比如在手机, body scroll 以后, address bar 会消失 (对 vh 影响). 或者在电脑内容多的时候会有 vertical scroll bar (对 vw 影响).
那游览器的 viewport size 是动态的吗 ?
先看看 Chrome 的历史: URL Bar Resizing
以前 Chrome 确实是动态的, 100vh 它会因为 address bar 的消失而改变 value. 但后来这种体验实在太差了. 所以被修改成固定的了.
Safari, Chome viewport size 都是不包含 address bar 和 tool bar 的.
固定 viewport size 的问题
参考: The trick to viewport units on mobile
由于 100vh = viewport size without address/tool bar. 所以当 address bar 存在的时候, 效果就会像左图那样.
所以用 vh, vw 时要切记. 它是不包含任何 bar 的高度/宽度 (偏大).
How to get read avaiable viewport ?
像 tesla.com 这种一屏一屏的体验, 如果用 100vh 就不对了. 因为 address bar 是一直存在的 (记住: 没有 bar 时 vh 美美, 有 bar 时 vh 不美).
有 2 种方法可以拿到包含 address bar 的 size (偏小).
参考:
Mobile issue with 100vh | height: 100% !== 100vh [3 solutions]
The trick to viewport units on mobile
CSS fix for 100vh in mobile WebKit
CSS fix for 100vh in mobile WebKit
第 1 种方式是不要用 vh, 改用 -webkit-fill-available.
.div { min-height: 100vh; /* fill on ios */ min-height: -webkit-fill-available; }
这个方法适合用在 first layer. 如果很多层就不合适了.
第 2 种方法是用 JS 获取 window.innerHeight 然后赋值给 CSS variable
window.addEventListener('resize', () => { document.querySelector(':root').style .setProperty('--vh', window.innerHeight/100 + 'px'); })
height: calc(100 * var(--vh));
调用, 10vh 等价于 10 * var(--vh)
假设 inner height 是 768px, 那么就是 10 x 768 = 7680px 所以 vh 需要先除于 100
最终就是 --vh = 768 / 100 = 7.68px, 然后 10vh = 10 * 7.68px = 76.8px.
监听 resize 的话基本上是模拟了 Chrome 早期 vh 的实现了.
Large, Small, Dynamic (lvh, svh, dvh)
参考: YouTube – Learn Every CSS Viewport Unit In 10 Minutes
lvh, svh, dvh 是新的东西, 目前支持率还不是很好. 29 Nov 2022 的 Chrome 才开始支持.
顾名思义 lvh 就是 large vh, 也就是不包含 address bar 的 vh (偏大). 也是目前的 vh
svh small vh 就是包含 address bar 的 vh (偏小), 目前需要用 JS 才能获取到的.
dvh 就是 dynamic vh, 当 address bar 出现时它就偏小, 当 address bar 消失时它就偏大. 它就是早年 Chrome 对 vh 的实现.
有了这些就不那么乱水了. oh yeah.
vmax, vmin, vb, vl
vmax 是拿 vh, vw 最大的那个
vmin 是拿 vh, vw 最小的那个
vb 是 view block, 它是 Logical Properties. 正常情况下是 vh
vi 是 view inline, 它是 Logical Properties, 正常情况下是 vw