【CSS in Depth 2 精译】2.4 视口的相对单位

当前内容所在位置

  • 第一章 层叠、优先级与继承
  • 第二章 相对单位
    • 2.1 相对单位的威力
    • 2.2 em 与 rem
    • 2.3 告别像素思维
    • 2.4 视口的相对单位 ✔️
    • 2.5 无单位的数值与行高
    • 2.6 自定义属性
    • 2.7 本章小结

2.4 视口的相对单位

前面介绍过的 emrem 是相对于 font-size 定义的,但相对单位并非只有这一类情况;还有一类 视口相对单位(viewport-relative units,用于定义相对于浏览器视口的长度。

视口的定义

视口(viewport) 是浏览器窗口中网页可见部分的边框区域。它不包括浏览器的地址栏、工具栏和(可能显示的)状态栏。

最近 CSS 语言对于视口相对单位又增加了一些新内容。目前 CSS 中总共有 24 个视口相对单元。这听起来可能让人难以接受(overwhelming),但它们都是由一些相对简单的概念通过多种方式的混搭而衍生出来的。本节将从最基本的知识点开始介绍。以下是最初添加到 CSS 语言中的四个基础视口相对单位:

  • vh —— 视口高度的 1%;
  • vw —— 视口宽度的 1%;
  • vmin —— 视口宽、高中较小的一方的 1%;
  • vmax —— 视口宽、高中较大的一方的 1%。

例如,50vw 等于视口宽度的一半,25vh 等于视口高度的 25%。vmin 取决于宽或高中尺寸较小的一方。这样就保证了元素始终都能适应屏幕尺寸,而与设备方向无关:横屏时 vmin 取决于视口高度;竖屏时则取决于视口宽度。

图 2.10 展示了一个正方形元素在不同屏幕尺寸的视口中的显示效果。它的宽高均为 90vmin,也就是两个维度中较小一方的 90%,即横屏时高度的 90%,或竖屏时高度的 90%。

图 2.10
图 2.10 宽高均为 90vmin 的元素,无论视口大小或方向如何,都会显示成一个稍小于视口的正方形

代码清单 2.14 为该元素的样式代码。无论浏览器如何缩放,最终都能得到一个适应视口的大正方形。在页面中添加一段 <div class= "square"> 就能看到效果。

代码清单 2.14 用 vmin 定义正方形元素的尺寸

.square {width: 90vmin;height: 90vmin;background-color: #369;
}

视口相对长度非常适合展示一个填满屏幕的大图。也可以将图片放在一个长容器内,给定高度为 100vh,理论上就能使其与视口高度完全一致。

当这些相对单位开始用于往视口填充大图后,人们发现一个问题:在移动设备上,视口的尺寸会动态变化。为了让屏幕可用尺寸最大化,移动端浏览器设计了这样一个功能:当用户向下滑动页面时,一些与用户体验相关的控件,如屏幕顶部的地址栏以及底部的导航按钮,会滑出视窗;而当用户向上滑动页面时,这些控件又会恢复显示。

这些动态变化会导致视口大小的缩放,进而改变页面上使用 vh 作单位的元素尺寸,并最终导致下方内容在屏幕上跳动。想象一下这样的场景:在用户向下滑过多个 100vh 的方盒后,又稍微向上翻了一下。这将导致视图中的所有内容猛地上窜几百个像素,带来极度不协调的阅读体验;况且还有性能问题——因为浏览器必须重新计算页面布局(通常称之为 布局抖动(layout thrashing)。

最终,大多数移动端浏览器都根据视口能够达到的最大尺寸重新解释了 vh,并忽略地址栏对视口尺寸的影响,从而阻止了该抖动行为。但有时开发人员可能并不想这样处理,因此 CSS 规范中又补充了几个相对单位。

2.4.1 从新的视口单位遴选

为了解决布局抖动的问题,CSS 引入了大视口(large viewports)和小视口(small viewports)的概念。大视口是在浏览器隐藏所有用户体验元素时的最大视口;而小视口则恰恰相反,是这些元素都正常显示时的浏览器最小视口(如图 2.11 所示)。

图 2.11
图 2.11 移动设备大小视口对比

与普通的视口单位一样,大视口单位也可用于设置宽度、高度、最小值和最大值。使用大视口单位,需在前面加上字母 l(即 large 的首字母小写):lvwlvhlvminlvmax;同理,前面加上字母 s(即 small 的首字母小写)则表示使用小视口单位:svwsvhsvminsvmax

有了这些新单元,开发人员就能根据当前场景遴选出更重要的行为模式:满屏高度的报头(masthead)是否必须占满整个屏幕,即便超出浏览器底部一点点也无所谓吗?如果是的话,就用 height: 100lvh;还是说,整个报头保持可见更重要,就算报头下方、屏幕底部会空出一点空间也无伤大雅?如果是的话,就用 height: 100svh

此外,以下注意事项也要牢牢记住:

  • 视口单位制没有考虑滚动条:也就是说,当存在垂直滚动条时,宽度为 100svw 的元素会产生水平滚动。
  • 当存在屏幕键盘时,关于小视口单位是否应该缩小屏幕尺寸,CSS 规范尚未明确规定。目前一些安卓浏览器是这样处理的,但 iOS 浏览器不是;未来可能还会变动。
  • 在绝大多数浏览器中,原始视口单位往往表现为大视口单位,但事无绝对。

这就又留下一个悬而未决的问题:某些情况下可能需要视口单位的原始行为,即当浏览器的用户体验元素出现或隐藏时,视口单位会动态切换。对于这种行为,CSS 提供了第三类视口相对单元:动态视口(dynamic viewport。启用它们,只需在视口单位前加上字母 d(即 dynamic 的首字母小写)即可:dvwdvhdvmindvmax。当视口较小时,其行为类似小视口单位;而当视口较大时,又类似大视口单元。

使用动态视口单位时务必慎之又慎——当用户在移动设备上下滚动页面时,一旦元素高度发生动态变化,很可能会出现布局抖动。

表 2.1 列出了所有可用的视口相对单位。为了完整起见,还包括一组额外的单位类型:内联(inline)与块(block)。这两种类型被称为“逻辑属性”,其行为分别类似于宽度和高度,但对于日语等垂直书写的语言,则需要对调一下。本书第 3 章还将深入介绍逻辑属性。

表 2.1 视口相对单位一览表

未指定视口(原始单位)大视口小视口动态视口
宽 / 高vw / vhlvw / lvhsvw / svhdvw / dvh
最小 / 最大vmin / vmaxlvmin / lvmaxsvmin / svmaxdvmin / dvmax
内联 / 块vi / vblvi / lvbsvi / svbdvi / dvb

除了上面提过的报头及其他类似的全屏或半屏元素之外,应该并没有充分的理由断言某种视口单位一定优于另一种视口单位。但由于可供选择的视口相对单元如此之多,可能还会让人有些无从下手。这种情况下,我会选择小视口单位。

2.4.2 使用视口单位定义字号

视口相对单位有一个不起眼的用途,就是设置字号。但我发现它比用 vhvw 设置元素的宽度和高度还要实用。

试想,给一个元素加上 font-size: 2svw 会发生什么?在一个 1200px 的台式机显示器上,字号的计算值为 24px(即 1200 的 2%);而在一个 768px 的平板设备上,计算值则为 15px(即 768 的 2%)。这么做的好处在于,该元素在两种尺寸之间可以平滑地过渡。这意味着字号不会在某个断点发生突变,而是随着视口尺寸的变化而逐渐过渡。

唯一美中不足的是,24px 的字号对台式屏幕太大了;更有甚者换到 iPhone SE 上,字号又会一直缩到仅有 7.5px 左右。如果能让字号保留这种缩放的能力,同时又能避免走极端就好了。为此,CSS 的 calc()clamp() 函数可以助您一臂之力。

1 利用 CALC() 函数实现响应式

calc() 函数可以对两个及以上的值进行基本四则运算。当涉及不同单位的值时,calc() 特别实用。其支持的运算包括:加(+)、减(-)、乘(*)、除(/)。其中加号和减号两边必须留有空白,因此建议大家养成在每个操作符前后都加上一个空格的习惯,比如 calc(1em + 10px)

以下代码利用 calc() 函数将 emsvw 单位相结合。从样式表中删除之前的基本字号,以及相关的媒体查询。换成以下样式代码:

:root {font-size: calc(0.5em + 1svw);
}

现在打开页面,慢慢缩放浏览器,字体也会平滑地缩放。 0.5em 保证了最小字号,而 1svw 则引入了一个响应式的标量。这样,基础字号就可以从 iPhone SE 上的 11.75px 一直过渡到 1200px 的浏览器窗口中的 20px

警告

在使用视口单位来计算字号时,一定要确保算式中包含 emrem 单位值,以提高页面的可访问性。这样一来,最终渲染出的字号就能兼顾用户自定义的字体设置。

您可以根据自己的喜好调整这些值,但要找到一个在小视口中不会太小、并在大视口中不会太大的理想值,可能还是有点困难。

2 利用 CLAMP() 函数加以完善

上面介绍的这种响应式字号很有用,但一个更新的 CSS 函数 clamp() 可以提供更精细的控制。clamp() 接受三个参数:最小值、以表达式形式给出的首选值、以及最大值。再次按以下样式更新页面:

:root {font-size: clamp(0.9rem, 0.6rem + 0.5svw, 1.5rem);
}

此时指定的字号为 0.6rem + 0.5svw ,但 clamp() 函数确保了最终结果不会小于 0.9rem,也不会大于 1.5rem。这样,即便遇到非常大或非常小的视口,也不会出现字号越界的情况。

既然字号是响应式的,那么页面上使用 emrem 定义的其他尺寸也可以响应式地同步缩放。这样,无需使用任何媒体查询,就完成了响应式策略的绝大部分工作。页面上的所有内容都将根据视口进行流畅缩放,而无需设置三四个硬编码的断点。响应式设计的内容远不止这些,后续章节还会进行更深入的探讨,但掌握这些知识必将为后续的设计工作开一个好头。

提示

min()max() 这两个相关函数可能时常也会用到。min() 函数表示给定值中的最小值(如 width: min(200px, 20svw););max() 则表示给定值中的最大值(如 min-height: max(200px, 20svw);)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/40267.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

rust + mingw安装教程

0. 说明 windows上安装rust时&#xff0c;需要在电脑上安装C/C构建工具。推荐的的两种工具链可以选择&#xff1a; visual studio build toolsmingw 官方推荐使用visual studio&#xff0c;若你的电脑上已经安装了visual studio&#xff0c;则无需再安装&#xff0c;直接安装…

单目相机减速带检测以及测距

单目相机减速带检测以及测距项目是一个计算机视觉领域的应用&#xff0c;旨在使用一个摄像头&#xff08;单目相机&#xff09;来识别道路上的减速带&#xff0c;并进一步估计车辆与减速带之间的距离。这样的系统对于智能驾驶辅助系统&#xff08;ADAS&#xff09;特别有用&…

基于tensorflow2的目标检测完整实现过程

序言 虽然tf1仍然在维护&#xff0c;但tf2毕竟是主流&#xff0c;如果不是项目有明确要求&#xff0c;建议直接选择tf2。本文以tf2为例展开&#xff0c;总结从环境准备到使用自己的数据和tensorflow预训练模型进行快速训练和调用。对tensorflow和目标检测算法有深入了解的&…

Vue+Xterm.js+WebSocket+JSch实现Web Shell终端

一、需求 在系统中使用Web Shell连接集群的登录节点 二、实现 前端使用Vue&#xff0c;WebSocket实现前后端通信&#xff0c;后端使用JSch ssh通讯包。 1. 前端核心代码 <template><div class"shell-container"><div id"shell"/>&l…

【FPGA】STA静态时序分析

文章目录 一.定义二.分类1. 静态时序分析2. 静态时序分析 三. 概念四. 时间余量1.场景2.建立时间余量3.保持时间余量 一.定义 时序分析:检查电路是否满足时序要求&#xff1b; 二.分类 1. 静态时序分析 STA,遍历所有的时序路径&#xff0c;根据时序库&#xff08;.lib文件&…

新手教学系列——使用uWSGI对Flask应用提速

在构建和部署Flask应用时,性能和稳定性是两个关键的因素。为了提升Flask应用的性能,我们可以借助uWSGI这个强大的工具。本文将详细介绍为什么要使用uWSGI、uWSGI的底层原理,并提供一个实例配置,帮助你更好地理解和应用这个工具。 为什么要使用uWSGI uWSGI 是一个应用服务…

探索企业知识边界,鸿翼ECM AI助手开启智慧问答新时代

在信息化迅速发展的当下&#xff0c;企业积累的数字文档数量巨大&#xff0c;这些文档中蕴含的深层信息对业务发展至关重要。然而&#xff0c;传统的搜索技术常常因只能进行关键字查询而无法满足对文档深层次理解的需求。 据Gartner调查&#xff0c;高达47%的员工在寻找有效工…

Webpack: 三种Chunk产物的打包逻辑

概述 在前文 Webpack: Dependency Graph 管理模块间依赖 中&#xff0c;我们已经详细讲解了「构建」阶段如何从 Entry 开始逐步递归读入、解析模块内容&#xff0c;并最终构建出模块依赖关系图 —— ModuleGraph 对象。本文我们继续往下&#xff0c;讲解在接下来的「封装」阶段…

【大数据】—美国交通事故分析(2016 年 2 月至 2020 年 12 月)

引言 在当今快速发展的数字时代&#xff0c;大数据已成为我们理解世界、做出决策的重要工具。特别是在交通安全领域&#xff0c;大数据分析能够揭示事故模式、识别风险因素&#xff0c;并帮助制定预防措施&#xff0c;从而挽救生命。本文将深入探讨2016年2月至2020年12月期间&…

24年河南特岗教师招聘流程+报名流程

河南特岗教师报名流程如下 1.登录河南省特岗招聘网 登录河南省特岗招聘网注册账号和密码&#xff0c;账号可以是手机号或者身份证号&#xff0c;密码自己设置 2.注册登录账号 注册完账号重新登录账号&#xff0c;输入身份证号、手机号、密码、验证码 3.浏览考试须知 填写个人信…

Python 编程快速上手——让繁琐工作自动化(第2版)读书笔记01 Python基础快速过关

Python 编程快速上手——让繁琐工作自动化&#xff08;第2版&#xff09;读书笔记01 Python基础快速过关 1 python基础概念 Python提供了高效的高级数据结构&#xff0c;还能简单有效地面向对象编程。 python运算符顺序 **——%——//——/——*——-——python中常见的数据…

Real-Time 3D Graphics with WebGL2

WebGL渲染管线 下图是WebGL渲染管线的示意图: Vertex Buffer Objects (VBOs) VBOS中包含了用于描述几何体的信息。如&#xff0c;几何体的顶点坐标&#xff0c;法线坐标&#xff0c;颜色&#xff0c;纹理坐标等。 Index Buffer Objects (IBOs) IBOs中包含了描述顶点关系的信…

C#的多线程UI窗体控件显示方案 - 开源研究系列文章

上次编写了《LUAgent服务器端工具》这个应用&#xff0c;然后里面需要新启动一个线程去对文件进行上传到FTP服务器&#xff0c;但是新线程里无法对应用主线程UI的内容进行更改&#xff0c;所以就需要在线程里设置主UI线程里控件信息的方法&#xff0c;于是就有了此博文。此文记…

Rocky Linux 9 快速安装docker 教程

前述 CentOS 7系统将于2024年06月30日停止维护服务。CentOS官方不再提供CentOS 及后续版本&#xff0c;不再支持新的软件和补丁更新。CentOS用户现有业务随时面临宕机和安全风险&#xff0c;并无法确保及时恢复。由于 CentOS Stream 相对不稳定&#xff0c;刚好在寻找平替系统…

idm 支持断点续传吗 idm 断点续传如何使用 idm断点续传怎么解决 idm下载中断后无法继续下载

断点续传功能&#xff0c;让我再也不会惧怕下载大型文件。在断点续传的帮助下&#xff0c;用户可以随时暂停下载任务&#xff0c;并在空闲时继续之前的下载进程。下载文件不惧网络波动&#xff0c;断点续传让下载过程更稳定。有关 idm 支持断点续传吗&#xff0c;idm 断点续传如…

JavaScript:if-else类型

目录 任务描述 相关知识 if语句 if-else语句 匹配问题 编程要求 任务描述 本关任务&#xff1a;根据成绩判断考试结果。 相关知识 在编程中&#xff0c;我们常常根据变量是否满足某个条件来执行不同的语句。 JavaScript中利用以if关键字开头的条件语句达到以上目的&am…

|从零搭建网络| VisionTransformer网络详解及搭建

&#x1f31c;|从零搭建网络| VisionTransformer系列网络详解及搭建&#x1f31b; 文章目录 &#x1f31c;|从零搭建网络| VisionTransformer系列网络详解及搭建&#x1f31b;&#x1f31c; 前言 &#x1f31b;&#x1f31c; VIT模型详解 &#x1f31b;&#x1f31c; VIT模型架…

mybatis、mybatis-plus插件开发,实现数据脱敏功能

首先说一下mybatis中四大组件的作用&#xff0c;下面开发的插件拦截器会使用 四大组件Executor、StatementHandler、ParameterHandler、ResultSetHandler Executor&#xff1a; Executor 是 MyBatis 中的执行器&#xff0c;负责 SQL 语句的执行工作。它通过调度 StatementHan…

python基础语法 004-3流程控制- while

1 while while 主要用的场景没有 for 循环多。 while循环&#xff1a;主要运行场景 我不知道什么时候结束。。。不知道运行多少次 1.1 基本用法 # while 4 > 3: #一直执行 # print("hell0")while 4 < 3: #不会打印&#xff0c;什么都没有print("…