简单聊下响应式布局
简单的从响应式布局的viewport介绍到读hexo博客的next主题的源码,来介绍下响应式布局。
viewport
谈到响应式,就离不开viewport。
移动端浏览器在一个通常比屏幕更宽的虚拟“窗口”(视口)中渲染页面,用户从而无须将所有页面都压缩进一个小屏幕里(那样会把很多没有针对移动端进行优化的站点打乱)。用户可以通过平移和缩放来浏览页面的不同区域。
两种viewport
- 布局视口(layout viewport)
- 视觉视口(visual viewport)
想象一下布局视口是一个足够大的而且不会改变尺寸和形状的图片,现在想象你有一个很小的框,你通过这个框来看上面那个足够大的图片。小框周围布满了不透明的材料,通过小框看到的大图就是视觉视口。你可以将小框向后移来观看所有的大图,也可以将小框靠近大图来观看大图的一部分。你也可以改变小框的方向,不过你要知道大图(布局视口)的形状和大小是从来没有改变的。
视觉视口(visual viewport)是在当前页面中显示屏幕的一部分。用户可能会滚动来改变他所看到的页面的一部分,或者通过缩放来改变视觉视口的尺寸。
然而,CSS布局,尤其是百分比宽度,是相对于布局视口计算的。布局视口比视觉视口宽的多。
因此<html>
元素最初获取布局视口的宽度,而且你的CSS被解释为宽度比手机宽的多,就相当于上面比喻中小框远离视觉视口的大图。这样可以确保你的页面布局的行为和桌面是一样的。
不同的浏览器用的默认layoutview的大小是多少呢?
- Safari iPhone 使用980px
- Opera 使用850px
- Android WebKit 使用800px
- IE 使用974px
在桌面端viewport
桌面端有一个有趣的现象,如果我们定义body中的子元素width:100%
,那么这100%相对于谁呢?对,相对于html,html的宽度又取决于viewport
,viewport
的宽度又相当于浏览器窗口的宽度。
上面的情况在100%zoom的时候显示正常,当我们缩放窗口的时候,viewport
小于页面的总宽度。页面本身没有关系,内容现在溢出超过<html>
,但是元素属性设置了overflow: visible
,这边是超出的内容也会展示出来。
下例中,蓝色的顶部栏由于设置了width: 100%
,所以浏览器会遵循viewport
所设置的宽度。这样蓝色的顶部栏并不管现在它太狭窄了。
缩放zooming
两种视口都是用来测量CSS像素,但是显然视觉视口的尺寸是根据缩放改变的(如果你放大,屏幕上的像素就会变少)。如果布局视口没有一直保持不变,那么百分比计算的宽度将会回流和重新计算。
了解布局视口
为了了解布局视口,我们需要关注一下页面完全缩小的情况。很多移动浏览器都是在完全缩放的情况下展示页面。这种情况下视觉视口等于布局视口。
因此布局视口的宽度和高度等于我们在完全缩放模式看到的。即使当用户放大窗口,布局视口也保持不变。
而且当你旋转手机到水平的时候,布局视口的内容也没有变,依旧是缩放到手机上面。这种情况有会导致一个问题,高度比横向少得多,不过网页开发者一般不关心页面的高度,只关心宽度。
下面罗列几个布局视口的宽度
属性 | 含义 |
---|---|
document. documentElement. clientWidth / Height | 布局视口尺寸 |
window.innerWidth/Height | 视觉视口尺寸 |
screen.width and screen.height | 屏幕尺寸 |
window.pageX/YOffset | 滚动偏移,和视觉视口相对于布局视口的值相同 |
document. documentElement. offsetWidth / Height | <html> 标签的尺寸 |
Media queries | 测量<html> 的宽度(width)或者设备的宽度(device-width)。 |
viewport Meta属性
这里让我们看一下<meta name="viewport" content="width=320">
的意义,这表示调整布局视口的尺寸。为了了解为什么这个属性这么重要,我们需要退后一步讨论。
假设你正在写一个简单的页面而且你没有设定你的元素的宽度。那么他们就会伸缩到布局视口宽度的100%。大多数浏览器都会将整个页面缩放来显示整个布局视口。像下图所示和缩放效果。
现在设置html {width: 320px}
的时候,<html>
将会收缩,所有的元素都会取320px的100%,但是这种情况只有用户放大页的时候才能得到,并不是初始化的状态。当用户缩小页面的时候,将会有大片的空白区域。
当你设置为<meta name="viewport" content="width=320">
的时候,初始化也显示正常了。你也可以设置任何你想要的宽度,包括device-width
。将会取得屏幕的宽度screen.width
(在设备像素中),于是布局视口将会使用这个值。
不过这里有一个问题,有时真正的screen.width
并没有起多大的作用,因为像素树太高了。例如, Nexus One 的屏幕像素是480px,不过谷歌工程师觉得给480px的宽度作为device-width
来说太大了。所以他们决定使用缩放到 2/3 ,所以device-width
所表达的宽度就是320px。
最后这里介绍下典型的针对移动端优化的viewport
1 | <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> |
width
控制视口的宽度。可以设置width=600这样的固定值,或者device-width这类的特殊值来指导比例为100%时屏幕宽度的CSS像素数值。
像素并非像素
许多手机都有物理像素都比页面的布局大得多,所以移动端将会以多个物理像素现已单个CSS像素。意味着initial-scale=1
在安卓或者ios手机上,都能显示较为接近的物理尺寸。
在240dpi及以上的屏幕上,initial-scale=1
的页面实际上会被Android WebKit浏览器放大至150%。其中的文字会保持平滑锐利,但是位图图像在全屏模式下就会不尽人意。为了使图片在这些屏幕上变得清晰,web开发者会将图片甚至整个布局设计成最终尺寸的150%(或者200%从而支持像配备retina屏的iPhone那样的像素密度高达320 dpi及以上的设备),然后通过CSS或视口属性缩小。
默认比例依赖于显示密度。在密度低于200dpi的显示设备上,比例为1.0。在密度介于200及300dpi之间的显示设备上,比例为1.5。对于具有300dpi以上密度的现实设备,比例为/150dpi向下取整。注意再有在视口比例为1时才会应用默认比例。否则,CSS像素与设备像素之间的关系依赖于当前的缩放等级。
next源码中响应式应用
hexo中的next主题是一个非常热门的blog主题,其中的相关源码是使用stylus书写的。
首先在文件夹外面定义了尺寸,这部分尺寸定义在需要修改样式的地方会进行修改。 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35mobile-smallest() {
@media (max-width: 413px) {
{block}
}
}
mobile-small() {
@media (max-width: 567px) {
{block}
}
}
mobile() {
@media (max-width: 767px) {
{block}
}
}
tablet() {
@media (min-width: 768px) and (max-width: 991px) {
{block}
}
}
desktop() {
@media (min-width: 992px) {
{block}
}
}
desktop-large() {
@media (min-width: 1600px) {
{block}
}
}
博客的左侧的页面导航在小于767的时候会隐藏,在大于767px的时候会在左上显示。这里展示部分代码:
1 | .site-nav-toggle { |
最后放下layout的布局stylus:
1 | .header { |
小结
因为blog的主要受众还是网页端,所以默认尺寸的填写时桌面端,再根据媒体查询开始往小尺寸开始。我看网上有说,页面优先从小尺寸开始写,这样比较适合响应式。不过我觉得应该根据页面的主要受众,来决定是优先移动端还是桌面端。太复杂的页面应该也不用写响应式,应该根据桌面端和移动端单独设计。
引用
- A Tale of Two Viewports
- A Tale of Two Viewports
- 在移动浏览器中使用viewport元标签控制布局
- [@media](https://developer.mozilla.org/zh-CN/docs/Web/CSS/@media)
- 本文标题:简单聊下响应式布局
- 本文作者:hddhyq
- 本文链接:https://hddhyq.github.io/2019/01/15/简单聊下响应式布局/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!