CSS - 响应式布局(一)媒体查询

news/2024/11/24 7:08:20/

目录

响应式布局

引子

理解响应式网页和响应式布局原理

媒体查询

什么是媒体查询?

什么是媒体类型?

什么是媒体特性?

媒体查询语法

仿三星官网首页


响应式布局

引子

通过前面两节的学习

CSS - 移动端布局(一)关键的前置知识_伏城之外的博客-CSDN博客

CSS - 移动端布局(二)移动端适配_伏城之外的博客-CSDN博客

我们已经了解如何开发能够适配移动端屏幕的网页,普适策略是使用meta viewport + rem布局 或 vw布局,但是这样开发出来的网页也仅仅只能适配移动端屏幕

 而无法适配PC端屏幕,当我们在PC端屏幕查看移动WEB网页时,实际效果如下:

导致移动网页在PC端显示效果不佳的原因是因为:

  • 移动WEB网页的宽度一般取移动浏览器视觉视口的宽度,当移动WEB网页在PC浏览器显示时,则其宽度也是取PC浏览器视觉视口的宽度,因此移动WEB网页在PC浏览器显示时会占满全屏
  • 移动WEB网页的布局尺寸一般都是动态尺寸,比如rem尺寸,vw尺寸,这些尺寸都与浏览器的视觉视口的宽度正相关,因此当浏览器从移动端的窄视口变为PC端的宽视口时,移动WEB网页的布局尺寸将同比放大,用户最直观的感受就是在PC浏览器上,移动WEB网页被放大了

因此,网站一般会避免用户在PC端访问移动WEB网页,同理,网站也会避免将PC网页放在移动端设备上展示,处理策略是:

  • 设计两套网页,一套PC WEB网页,一套移动WEB网页
  • 当用户访问网站网页时,网站服务器会判断用户发送的请求是来自PC浏览器,还是移动浏览器(根据HTTP请求头中的User-Agent),如果是移动浏览器,则响应移动WEB网页,如果是PC浏览器,则响应PC WEB网页

当请求来自PC浏览器时,请求头中User-Agent信息如下

当请求来自移动浏览器时,请求头中User-Agent信息如下 

但是这种处理策略,需要网站维护两套网页,甚至维护两套网站,在设计、开发和运维成本上都是double的,这是缺点。当然烧钱的东西,肯定是有优点的,如果维护两套网站的话,即一套服务于PC端用户的网站,一套服务于移动端用户的网站,公司就可以根据用户流量来合理安排服务器资源,避免资源浪费或资源竞争,另外对于前端开发来说不需要在一个网页中同时实现适配PC浏览器和移动浏览器,开发难度也会大大降低。

当然,上面这种策略是大公司、大网站才需要玩的,对于小公司,小网站来说,这种烧钱的策略是没必要的。因此,一套网页同时支持适配PC和移动端的技术是有必要研究的,而我们将同时能够适配PC端和移动端的网页称为响应式网页。

理解响应式网页和响应式布局原理

三星电子 中国 | 三星手机 | 电视 | 显示器 固态硬盘 | 冰箱 洗衣机等产品官网 (samsung.com)

三星的官网首页就是一个响应式网页,即该网页既支持适配PC端,又支持适配移动端。

如下是该网页在PC端1920x1080分辨率下的显示效果

如下是该网页在平板768x1024分辨率下的显示效果

如下是该网页在手机375x812分辨率下的显示效果

我们可以发现,响应式网页无论在PC端,还是在平板、手机这些移动端设备上都能够实现良好适配,并且这种适配并不需要改变网页的内容结构(HTML),只需要改变网页内容的布局(CSS),比如上面三个截图中网页的内容并未发生改变,只是网页内容的布局发生了改变。

而我们将可以随着浏览器视觉视口分辨率的改变而改变的网页布局,称为响应式布局。

因此响应式布局的原理很简单,那就是监听浏览器视觉视口宽度的变化,当浏览器视觉视口宽度变化到一定程度或一定范围内时,网页的布局就改变,即网页采用另一套样式。

而监听浏览器视觉视口宽度的变化,我们最先想到的就是通过JS的事件,如window.onload和window.onresize,下面我们来通过JS实现一个简单的响应式布局

JS事件监听触发响应式布局-Javascript文档类资源-CSDN文库

HTML部分

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}</style><link rel="stylesheet" id="responsive" /><script>const selectStyle = () => {const viewportWidth = document.documentElement.clientWidth;const stylesheet = document.querySelector("#responsive");if (viewportWidth >= 1440) {stylesheet.href = "./min1440.css";} else if (viewportWidth >= 768) {stylesheet.href = "./min768.css";} else {stylesheet.href = "./max768.css";}};window.onload = selectStyle;window.onresize = selectStyle;</script></head><body><br /><div class="w"><div class="footer-nav"><input type="checkbox" id="product-service" style="display: none" /><dl><dt><label for="product-service">产品与服务</label></dt><dd>智能手机</dd><dd>智能平板</dd><dd>音频设配</dd><dd>智能手表</dd><dd>S 换机助手</dd><dd>智能产品配件</dd><dd>电视</dd><dd>冰箱</dd><dd>洗衣机</dd><dd>空调</dd><dd>显示器</dd><dd>存储产品</dd></dl><input type="checkbox" id="purchase-channels" style="display: none" /><dl><dt><label for="purchase-channels">购买渠道</label></dt><dd>最新活动</dd><dd>网上商城</dd><dd>三星Galaxy授权体验店</dd><dd>电视/影音产品门店查询</dd><dd>冰箱/洗衣机产品门店查询</dd><dd>非全新机</dd><dd>官方翻新机</dd></dl><input type="checkbox" id="service-support" style="display: none" /><dl><dt><label for="service-support">服务支持</label></dt><dd>在线服务</dd><dd>邮件咨询</dd><dd>联系我们</dd><dd>服务中心查询</dd><dd>体验反馈</dd><dd>ECO信息</dd><dd>三星中国开发者</dd><dd>专属管家服务</dd><dd>尊贵管家服务</dd></dl><input type="checkbox" id="about-us" style="display: none" /><dl><dt><label for="about-us">关于我们</label></dt><dd>公司介绍</dd><dd>业务范围</dd><dd>品牌标识</dd><dd>人才招聘</dd><dd>投资者关系</dd><dd>新闻中心</dd><dd>伦理道德</dd></dl></div></div></body>
</html>

min1440.css

/* 当浏览器视觉视口宽度 >= 1440 时,采用如下样式 */.w {width: 1440px;margin: 0 auto;
}.footer-nav {width: 100%;border-top: 1px solid #ddd;border-bottom: 1px solid #ddd;display: grid;grid-template-columns: repeat(4, 1fr);grid-template-rows: 1fr;
}.footer-nav > dl:not(:last-child) {padding-bottom: 32px;border-right: 1px solid #ddd;
}.footer-nav > dl > dt {padding: 16px 24px;font-size: 18px;font-weight: bold;
}.footer-nav > dl > dd {padding: 7px 24px;font-size: 14px;cursor: pointer;
}.footer-nav > dl > dd:hover {text-decoration: underline;color: #1428a0;
}

min768.css

/* 当浏览器视觉视口宽度在 [768, 1440) 时,采用如下样式 */.w {width: 100%;
}.footer-nav {width: 100%;border-top: 1px solid #ddd;border-bottom: 1px solid #ddd;display: grid;grid-template-columns: repeat(4, 1fr);grid-template-rows: 1fr;
}.footer-nav>dl:not(:last-child) {padding-bottom: calc(100vw / 1440 * 32);border-right: 1px solid #ddd;
}.footer-nav>dl>dt {padding: calc(100vw / 1440 * 16) calc(100vw / 1440 * 24);font-size: calc(100vw / 1440 * 18);font-weight: bold;
}.footer-nav>dl>dd {padding: calc(100vw / 1440 * 7) calc(100vw / 1440 * 24);font-size: calc(100vw / 1440 * 14);cursor: pointer;
}.footer-nav>dl>dd:hover {text-decoration: underline;color: #1428a0;
}

 max768.css

/* 当浏览器视觉视口宽度 < 768 时,采用如下样式 */.w {width: 100%;
}.footer-nav {width: 100%;border-top: 1px solid #ddd;
}.footer-nav > dl > dt {margin: 0 calc(100vw / 767 * 25);padding: calc(100vw / 767 * 36) calc(100vw / 767 * 25);border-bottom: 1px solid #ddd;font-size: calc(100vw / 767 * 34);font-weight: 700;
}.footer-nav > dl > dt > label {cursor: pointer;user-select: none;
}.footer-nav > dl > dd {display: none;padding: calc(100vw / 767 * 21) calc(100vw / 767 * 59.6) calc(100vw / 767 * 21) calc(100vw / 767 * 68);font-size: calc(100vw / 767 * 29.8);cursor: pointer;
}.footer-nav > dl > dd:hover {text-decoration: underline;color: #1428a0;
}#product-service:checked + dl > dd,
#purchase-channels:checked + dl > dd,
#service-support:checked + dl > dd,
#about-us:checked + dl > dd {display: block;
}#product-service:checked + dl > dt,
#purchase-channels:checked + dl > dt,
#service-support:checked + dl > dt,
#about-us:checked + dl > dt {border-bottom: none;
}

实现效果如下:

当浏览器视觉视口宽度 >= 1440 时

当浏览器视觉视口宽度在 [768, 1440) 时 

 

当浏览器视觉视口宽度 < 768 时 

 通过上面的实操,我们可以总结出响应式布局的实现原理,其实就是为一个网页结构设计多套样式,这里的多套样式需要能够使网页适配不同分辨率的屏幕。

但是,上面通过JS监听浏览器视觉视口宽度变化的方式促发响应式布局,非常不优雅,而当我们使浏览器视觉视口resize时,网页布局会出现抖动,这里的抖动其实是:JS监听到了视觉视口的宽度变化,然后触发onresize事件回调,卸载当前样式文件,然后加载新的样式文件。

而闪动的原因就是JS卸载样式文件时,网页会处于无样式的裸奔状态,虽然时间很短,但是也会出现,而后加载完新的样式文件后,网页有了样式,当视觉视口不断地resize时,网页就会不断卸载样式、加载样式,此时我们就可以看到明显的布局抖动。

 因此,通过JS来触发响应式布局,并不是一种好的方式。

为了实现平滑、顺畅、无抖动的响应式布局,CSS3推出了媒体查询。

媒体查询

什么是媒体查询?

媒体查询,即media query,它是一种CSS语法,支持:

  • 针对不同的媒体类型(media type)定义不同的样式
  • 针对某媒体类型下不同的媒体特性(media feature)定义不同的样式

什么是媒体类型?

早期,网页不仅可以在电脑浏览器上显示,还可以在打印机中打印,还可以在投影仪上投影,以及在电视上显示等等,而这里的电脑、打印机、投影仪、电视就是媒体,后期,网页越来越多地在手机、平板等移动端设备上显示,而这里地手机、平板也是媒体,为了更好的区分这些媒体,CSS将它们划分为了以下几个媒体类型:

  • screen :屏幕媒体,包括电脑、手机、平板
  • print:打印媒体,如打印机
  • projection:投影媒体,如投影仪
  • tv:电视媒体,如电视
  • all:所有媒体

但是,上述几个媒体类型中投影媒体和电视媒体几乎已经不用了,因此主要的媒体类型就三个 screen、print、all,其中screen是最最常用的媒体类型。

什么是媒体特性?

我们大多只关注screen媒体类型的媒体特性,screen媒体类型的常用特性有如下三个:

min-width视觉视口的最小宽度
max-width视觉视口的最大宽度
orientation屏幕处于横屏(landscape)还是竖屏(portrait)

媒体查询语法

媒体查询可以定义在三个地方:

  • link标签属性中
  • @import url语法中
  • @media语法中

link标签属性中定义媒体查询的语法如下:

<link rel="stylesheet" href="./min1440.css" media="screen and (min-width: 1440px)">
<link rel="stylesheet" href="./min768.css" media="screen and (min-width: 768px) and (max-width: 1439px)">
<link rel="stylesheet" href="./max768.css" media="screen and (max-width: 767px)">

将媒体查询定义在link标签的media属性中,如上三个link标签的含义分别为:

  • 当媒体类型为screen时(即电脑、手机、平板),且(and语义) 浏览器视觉视口宽度最小不低于1440px时(即≥1440px),应用./min1440.css到网页中
  • 当媒体类型为screen时,且浏览器视觉视口宽度范围在  [768px, 1439px] 时,应用./min768.css到网页中
  • 当媒体类型为screen时,且浏览器视觉视口宽度最大不超过 767px时(即≤767px),应用./max768.css到网页中

link标签定义媒体查询不是一种推荐方式,当存在大量媒体查询时,会产生大量link标签,这样不仅不美观,还会阻塞JS的加载执行,进而影响整体网页的渲染速度。

@import url语法定义媒体查询的语法如下:

@import url可以定义在HTML的style标签中,也可以定义在css文件中

<style>@import url(./min1440.css) screen and (min-width: 1440px);@import url(./min768.css) screen and (min-width: 768px) and (max-width: 1439px);@import url(./max768.css) screen and (max-width: 767px);
</style>

上面三句@import中添加的媒体查询含义和前面一致

由于@import会等到所有JS加载执行完毕后,才会加载css文件,因此不会阻塞网页的渲染,因此我们推荐在@import语法中定义媒体查询。但是@import只能针对样式文件进行操作,不能针对单个样式或局部样式进行操作,因此我们还需要借助第三种媒体查询定义方式@media。

@media定义媒体查询的语法如下:

<style>@media screen and (min-width: 1440px) {.w {width: 1440px;margin: 0 auto;}.footer-nav {width: 100%;border-top: 1px solid #ddd;border-bottom: 1px solid #ddd;display: grid;grid-template-columns: repeat(4, 1fr);grid-template-rows: 1fr;}.footer-nav > dl:not(:last-child) {padding-bottom: 32px;border-right: 1px solid #ddd;}.footer-nav > dl > dt {padding: 16px 24px;font-size: 18px;font-weight: bold;}.footer-nav > dl > dd {padding: 7px 24px;font-size: 14px;cursor: pointer;}.footer-nav > dl > dd:hover {text-decoration: underline;color: #1428a0;}}@media screen and (min-width: 768px) and (max-width: 1439px) {.w {width: 100%;}.footer-nav {width: 100%;border-top: 1px solid #ddd;border-bottom: 1px solid #ddd;display: grid;grid-template-columns: repeat(4, 1fr);grid-template-rows: 1fr;}.footer-nav > dl:not(:last-child) {padding-bottom: calc(100vw / 1440 * 32);border-right: 1px solid #ddd;}.footer-nav > dl > dt {padding: calc(100vw / 1440 * 16) calc(100vw / 1440 * 24);font-size: calc(100vw / 1440 * 18);font-weight: bold;}.footer-nav > dl > dd {padding: calc(100vw / 1440 * 7) calc(100vw / 1440 * 24);font-size: calc(100vw / 1440 * 14);cursor: pointer;}.footer-nav > dl > dd:hover {text-decoration: underline;color: #1428a0;}}@media screen and (max-width: 767px) {.w {width: 100%;}.footer-nav {width: 100%;border-top: 1px solid #ddd;}.footer-nav > dl > dt {margin: 0 calc(100vw / 767 * 25);padding: calc(100vw / 767 * 36) calc(100vw / 767 * 25);border-bottom: 1px solid #ddd;font-size: calc(100vw / 767 * 34);font-weight: 700;}.footer-nav > dl > dt > label {cursor: pointer;user-select: none;}.footer-nav > dl > dd {display: none;padding: calc(100vw / 767 * 21) calc(100vw / 767 * 59.6)calc(100vw / 767 * 21) calc(100vw / 767 * 68);font-size: calc(100vw / 767 * 29.8);cursor: pointer;}.footer-nav > dl > dd:hover {text-decoration: underline;color: #1428a0;}#product-service:checked + dl > dd,#purchase-channels:checked + dl > dd,#service-support:checked + dl > dd,#about-us:checked + dl > dd {display: block;}#product-service:checked + dl > dt,#purchase-channels:checked + dl > dt,#service-support:checked + dl > dt,#about-us:checked + dl > dt {border-bottom: none;}}
</style>

在@media中,我们可以为某些媒体类型、媒体特性定义单个或多个样式,灵活性更高。

无论使用哪种方式定义媒体查询,我们需要注意如下几点:

  • 媒体查询中,媒体类型是必要条件,必须定义
  • 媒体查询中,媒体特性是次要条件,可以不定义,如果定义的话,则必须用小括号括起来,且一个小括号中只能定义一个媒体特性
  • 媒体查询中,媒体类型和媒体类型之间,媒体类型和媒体特性之间、媒体特性与媒体特性之间需要使用逻辑操作符用关联,逻辑操作符即常用的“与”、“或”、“非”、“仅”

媒体查询中的逻辑操作符介绍:

  • “与”:and
  • "或":,
  • “非”:not
  • "仅":only

我们通过几个实例来理解媒体查询中的逻辑操作符:

@import url(./min768.css) screen and (min-width: 768px) and (max-width: 1439px);

上面媒体查询含义是:当  “媒体类型为screen 视觉视口宽度≥768px 视觉视口宽度≤1439px” 时,才应用min768.css到网页。

@import url(./min768.css) screen,print;

上面媒体查询含义是:当  “媒体类型为screen print ,才应用min768.css到网页。

@import url(./min768.css) screen and (max-width: 768px), screen and (min-width: 1439px);

上面媒体查询含义是:当 “媒体类型为screen 且 视觉视口宽度≤768px“  或者   “媒体类型为screen 且 视觉视口宽度≥1439px“

我们需要注意的是,”或“逻辑操作符,如果在媒体特性后面加逗号,表示媒体查询结束,逗号后面将定义一个新的媒体查询。

@import url(./min768.css) not screen;

上面媒体查询含义是:如果媒体类型为screen,则不应用样式。

@import url(./min768.css) not screen and  (min-width: 768px) and (max-width: 1439px);

上面媒体查询含义是:如果媒体类型为screen,且视觉视口宽度≥768px, 且视觉视口宽度≤1439px 时,则应用样式,其余情况则应用样式。

我们需要注意的是not目前只能用于否定整个媒体查询的条件,不能用于否定单个媒体功能表达式,因此not一般写在媒体类型前面。

@import url(./min768.css) only screen and  (min-width: 768px) and (max-width: 1439px);

上面媒体查询含义是:仅在“媒体类型为screen 视觉视口宽度≥768px 视觉视口宽度≤1439px”时,应用min768.css样式文件到网页。

我们需要注意的是,only只能用于限制整个媒体查询,不能用于限制单个媒体功能表达式,因此only的逻辑操作功能很鸡肋,但是only还有一个妙用,那就是当浏览器不支持媒体功能时,浏览器会忽略除媒体类型之外的媒体查询条件

@import url(./min768.css) screen and  (min-width: 768px) and (max-width: 1439px);

对于上面的媒体查询,低版本浏览器会理解为 @import url(./min768.css) screen,即只要媒体类型是screen,即应用min768.css,显然这是不对的。但是如果我们加上only限定,

@import url(./min768.css) only screen and  (min-width: 768px) and (max-width: 1439px);

则此时低版本浏览器就会被排除在外,无法使用媒体查询暴露的样式。

如果想要制定复杂的媒体查询,可以参考MDN的使用媒体查询 - CSS(层叠样式表) | MDN (mozilla.org)

仿三星官网首页

响应式网页布局-仿三星官网首页-HTML5文档类资源-CSDN文库

在进行响应式网页开发过程中,我们会面临如下问题:

  • 媒体查询的粒度问题

所谓媒体查询的粒度,即媒体查询成功匹配后,加载给网页的样式的是作用于整个网页的,还是作用于网页中某个局部组件的,比如:

上面例子中每个媒体查询的对应样式就是作用于整个网页的。

 上面例子中,媒体查询只针对网页中某个局部组件。

如果从可维护性上来说,媒体查询的粒度越小越好,针对组件定义媒体查询,可以实现分工合作开发,并且发生问题时,可以根据问题所在组件来缩小问题范围,加速问题定位和解决。

如果代码复杂度上来说,媒体查询的粒度越小,则需要的媒体查询就越多,比如前面例子中,针对整个网页的媒体查询只需要4个,而针对组件的媒体查询可能需要 组件个数 x 4,这不仅浪费性能,而且非常容器造成各组件之间媒体查询条件定义不一致,产生混乱。

 因此,媒体查询的粒度大小选择,需要根据实际情况来定。

  • 媒体查询的样式复用问题

无论是针对整体网页的媒体查询,还是针对网页局部组件的媒体查询,都存在样式是否需要复用的问题。

比如三星官网首页的响应式布局中,视觉视口宽度≥1440px  和 视觉视口在[768px, 1439px]范围时,除了尺寸样式的尺寸等比例缩小外,其余样式均不变,这意味着两个媒体查询中存在大量重复的样式定义。

如果[768px, 1439px]媒体查询  复用了 [1440px, +∞)媒体查询 的样式,那么一旦 [1440px, ∞)媒体查询 的样式改变,则会直接影响[768px, 1439px]媒体查询 的样式。

如果不复用的话,媒体查询中则又会产生大量重复定义的样式,但是没有了耦合影响。

此时,我们其实需要关注两个媒体查询对应样式的关联程度,如果关联度高的话,则可以复用;如果关联度低的话,则不要复用。

什么是关联度?

即网页布局的变化是否很大,比如三星官网首页 [1440px, +∞),变为[768px, 1439px]时,网页布局并未发生较大变化,只是网页内容等比例缩小了而已,此时媒体查询之间就可以复用样式。但是三星官网首页从[768px, 1439px] 变为 [0, 767px] 时,网页布局发生了较大变化,差不多是从PC网页布局变为了移动端网页布局,此时,媒体查询之间就没有了样式复用的必要。


http://www.ppmy.cn/news/583683.html

相关文章

别克GL8,这样的改装太令人兴奋了

别克GL8一直深受广大爱车人士的喜爱&#xff0c;别克GL8的改装也是层出不穷&#xff0c;下面我们一起来看看这款的改装吧&#xff01; 前脸换上了“雅典娜”的前脸&#xff0c;视觉效果非常棒&#xff0c;不仅在格栅的设计上极其夸张&#xff0c;它的内饰更是可完全比肩商务舱&…

Python学习笔记:第四站 往哪走

Python学习笔记 文章目录 Python学习笔记第四站 往哪走1. 程序的组织结构2. 顺序结构3. 对象的布尔值4. 分支结构5. pass空语句6. 本章作业 课程笔记参考B站视频&#xff1a; Python全栈开发教程。 第四站 往哪走 1. 程序的组织结构 1996年&#xff0c;计算机科学家证明了这…

当我们老了,又会怎样

最近在看《我们仨》&#xff0c;一本杨绛先生的散文集。 这本书分为了三部分。第一部分算是个引子&#xff0c;就杨绛先生晚年的一个梦开始&#xff0c;以梦中“钟书大概是记着‘我’的埋怨&#xff0c;叫‘我’做了一个长达万里的梦”拉开全文序幕&#xff1b;第二部分则是描…

第 350 场周赛

A 总行驶距离 纯模拟 class Solution { public:int distanceTraveled(int mainTank, int additionalTank) {int res 0;while (1) {if (mainTank > 5) {res 50;mainTank - 5;if (additionalTank) {additionalTank--;mainTank;}} else {res mainTank * 10;break;}}return …

史上最极品美女乞丐,难道是犀利姐来了?(有图有真相)

昨天在街上闲逛&#xff0c;突然发现路边有个乞丐&#xff0c;跟犀利哥的造型一模一样&#xff01;我K&#xff0c;这年头连乞丐都会追星了&#xff01;仔细一看&#xff0c;丫还是个女的&#xff0c;还挺面熟的。再仔细的看了一眼&#xff0c;晴天霹雳&#xff01;居然是那个讲…

美女搭讪

星期天电磁炉坏了,中午去快餐店吃饭&#xff0c;一个人啊&#xff0c;无奈。 吃着吃着&#xff0c;突然有个美女过来。 她跟我说&#xff1a;一个人么&#xff1f;我脱口而出&#xff1a;对啊 我当时老开心了&#xff0c;居然有美女来搭讪。 结果&#xff0c;结果。。。。 …

经典SQL语句大全二:提升

1、说明:复制表(只复制结构,源表名:a 新表名:b) (Access可用) 法一:select * into b from a where 1<>1(仅用于SQlServer)法二:select top 0 * into b from a2、说明:拷贝表(拷贝数据,源表名:a 目标表名:b) (Access可用) insert into b(a, b, c) select d,e,f …