整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

大型网站前端架构,深入每个网页本身,处理适配性和兼容性问题

配性和兼容性

在前面介绍了整体前端工程的一些规范化原则及做法,这样基本上可以保证前端工程的内部不会过度混乱。

本节我们将深入每个网页本身,处理适配性和兼容性问题。适配性指的是页面对浏览器大小的适配,兼容性指的是网页对于不同浏览器的兼容。

同样介绍了网页适配性和兼容性的必要性,下面介绍具体的解决方法。

注意:在项目前期需要规划好网页运行的浏览器(包括PC端和手机端),这样可以在开发阶段和单元测试时尽早发现适配性和兼容性问题,在项目开发过程中消化这些琐碎的工作。

响应式布局

适配性指的是网页对浏览器大小的适配,虽然很多时候大型网站都会独立出PC网页和手机网页两部分(也有可能根据不同展示端独立出更多的部分),但是不可避免的是,同类型设备的分辨率会有差别,PC浏览器窗口大小也可以随意调整,这些因素都会影响网页的显示。一个适配性不好的网页,会经常出现网页元素错位等不良现象,极度影响用户体验。

为了解决适配性问题,响应式布局的概念被提出。响应式布局就是一个网页能够兼容多个终端,如图3.35所示。

图3.35 响应式布局的网页

响应式布局有很多具体的实现方法,如Flex弹性布局、Grid网格布局、Bootstrap的栅格系统等。但是,很多时候这些响应式布局方法并不能很好地解决网页适配性的问题。问题的关键并不是这些响应式布局的方法不够好,而是使用者本身对网页的布局没有一个正确的认知,如图3.36所示。

图3.36 错误的网页布局认知

在图3.36中确实是一个完整的骨架图,也表现出了所有网页元素的布局,但是这样的布局认知却是无法做好网页布局的。因为这种布局认知太过于具体,所以在实现响应式布局的时候就需要顾及太多的细节,导致无法很好地实现响应式布局。就好像“把大象放进冰箱一共需要几步”这个问题一样,我们不应该一开始就着眼于全部细节(思考怎么锯开大象),而是应该从宏观上审视这个问题,把大象抽象成一个物品,那么我们就很容易得出“打开冰箱—把大象装进去—关冰箱门”这样的答案,至于怎么把大象塞进去,那是“把大象装进去”这个步骤中的细节。同理,正确的网页布局认知应该是有层次的,这里把网页布局分成两层,即整体层和模块层,如图3.37所示。

图3.37 把网页布局分成两层

整体层是忽略页面的细节,在整体上把网页分成合理的几个模块(区域);模块层是各模块分区的具体细节。

说明:对布局分层只是对布局的思考方式,在画网页骨架图时,还是类似于图3.36那样比较好一些。

整体布局

响应式布局中提到整体层是忽略页面的细节,在整体上考虑页面各分区的布局。这里一个网页需要适配不同的终端,包括PC浏览器和手机浏览器。

虽然设备分辨率是各式各样的,但是可以按照浏览器横向分辨率将其划分为小屏手机(<576px)、手机(≥576px)、平板(≥768px)、桌面显示器(≥992px)和大桌面显示器(≥1200px)。很多时候,对于整体布局而言,小屏手机和手机的整体布局是一致的,平板、桌面显示器和大桌面显示器的整体布局是一致的,所以我们大部分时候只需要关注768px这个分水岭就可以了。

注意:这里说的浏览器分辨率和设备分辨率是有区别的。比如iPhone4的手机分辨率是960×640px,而iPhone 4上Safari浏览器的分辨率是320×480px。浏览器分辨率可以通过$(document).width()和$(document).height()获取。

综上,本节需要实现的整体布局如图3.38所示,其中翻页区域在手机浏览器中需要隐藏。

图3.38 需要实现的整体布局

1.原生HTML开发

使用原生HTML开发当然是可以实现响应式布局的,CSS文件中可以设置样式生效的浏览器的横向分辨率,但是比较推荐的方法是根据浏览器的横向分辨率设置两个独立的CSS文件,网页会自动根据分辨率引用不同的CSS文件。HTML文件引用CSS文件的方式如代码3.24所示,其中当浏览器的横向分辨率小于768px时,styleA.css的样式会生效;当浏览器的横向分辨率大于等于768px时,styleB.css的样式生效。

代码3.24 HTML文件根据浏览器横向分辨率引用CSS文件的方式

<link rel="stylesheet" href="styleA.css" media="screen and (max-width:

767px)">

<link rel="stylesheet" href="styleB.css" media="screen and (min-width:

768px)">

2.Bootstrap栅格系统

使用原生HTML开发能很好地应对网页适配性,但是整个网站都通过这种方式实现适配性的话将会是一件麻烦的事情。因为一般手机页面的整体布局就是竖排的,而且768px这个分水岭是基本固定的,所以每个网页都定制这样的样式会显得特别烦琐。

在3.3.3小节中提到的Bootstrap,其提供的栅格系统便是目前比较流行的响应式布局解决方案。

注意:在使用栅格系统之前,不要使用table元素作为布局的工具。这是因为基本上现有的响应式布局方法都不支持对table元素的调整。

下面对Bootstrap的栅格系统进行说明。在引用Boostrap必要的JavaScript文件和CSS文件后即可使用栅格系统,用栅格系统实现整体布局的例子如代码3.25所示,其中,这里只设置了div的宽度,因为栅格系统本身不提供高度的设置,高度的设置在之后会讲解。

代码3.25 HTML文件根据浏览器的横向分辨率引用CSS文件的方式

<head>

<!--设置此网页信息后,网页才会随设备大小变化,否则,网页的默认最小宽度为980px-->

<meta name="viewport" content="width=device-width, initial-scale=1">

</head>

<body>

<!--栅格系统的容器div,会铺满父区域的宽度-->

<div class="container-fluid">

<div class="row"> <!--栅格系统的行div -->

<div class="col-sm-12">搜索区域</div> <!--搜索区域div -->

<div class="col-sm-12">资源列表区域</div> <!--资源列表区域div -->

<!--翻页区域div -->

<div class="col-sm-12 d-none d-sm-block">翻页区域</div>

</div>

</div>

</body>

代码3.25中,<div class="container-fluid"></div>和<divclass="row"></div>是使用栅格系统前必须引入的,这两个div中的内容才是图3.38显示的内容。

Bootstrap的栅格系统把屏幕的宽度分成12等份,我们只需要选择几个等份的宽度即可。例子中col-sm-12指的是浏览器分辨率的宽度大于等于768px的情况下,铺满12份(100%宽度)。这里由于没有设置浏览器的横向分辨率小于768px的情况,所以在此情况下会默认铺满12份。“d-none d-sm-block”指的是浏览器的横向分辨率小于768px的情况下,隐藏起来。需要注意的是,dnone d-sm-block是Bootstrap 4的做法,在Bootstrap 3版本下有其他设置方式。Bootstrap栅格系统更详细的说明见官方文档https://v4.bootcss.com/docs/layout/overview/。

这里出现了一个问题,栅格系统的12等分看起来很难精确地还原UI设计,除非UI设计中的整体布局也是恰巧按照12等分设计的。其实网页无论怎么实现,都很难百分百还原UI设计。这是因为UI设计是基于固定分辨率制作的图片,而网页是不可能只在一个分辨率下显示的,所以UI设计中很多经过精心计算的尺寸都很难在网页中百分百实现。对于网页美观性而言,更多的是着重于细节(如字体大小、组件美化等),而整体布局,只需要大概趋近比例即可。

如果整体布局的比例需要很严格地按照UI设计的比例实现,那么Bootstrap的栅格系统不太合适,需要使用其他布局方式进行实现,如Grid网格布局等。

3.整体布局的模块高度

在很多响应式布局方法中,尤其是Bootstrap的栅格系统,高度的描述是经常被忽略的,这是因为响应式布局要求一个网页适配多个终端,高度默认是作为宽度变化的补偿。也就是说,如果某块网页内容在一些分辨率中是一行显示,而宽度变窄了之后只能两行显示的话,高度需要自动变化,只有这样才能把内容显示完全。因此,响应式布局一般不需要设置固定的高度,让高度自动变化即可。

但是,一些网页的设计(尤其是PC网页)是一屏设计(没有滚动),本小节需要实现的整体布局也是一屏设计,这样的话,高度的描述就不能被忽视。

那么整体布局需要如何应对这种一屏设计呢?一般的做法是固定一些模块的高度,其他模块再铺满这个页面。具体代码如下所示,其中CSS设置如代码3.26所示,HTML如代码3.27所示。

代码3.26 CSS设置

/* 设置网页的大小铺满整个窗口 */

.Page_body{

position: absolute;

height:100%;

width: 100%;

}

/* 设置栅格系统的container和row的高度为父区域的100% */

.Body_Container{

height:100%;

margin:0px;

}

/* 设置搜索区域的高度为50px */

.Body_Search {

height:50px;

background:gray;

}

/* 设置资源列表区域的高度铺满网页剩下的高度 */

.Body_Resource {

height:calc(100% - 50px - 50px - 20px);

margin-bottom: 10px;

margin-top: 10px;

background:gray;

}

@media (max-width: 767px) { /* 设置当翻页区隐藏时,资源列表区域的高度 */

.Body_Resource {

height:calc(100% - 50px - 10px);

margin-bottom: 0px;

}

}

/* 设置翻页区域的高度为50px */

.Body_Page {

height:50px;

background:gray;

}

代码3.27 HTML部分

<head>

<!--设置此网页信息后,网页才会随设备大小变化,否则,网页的默认最小宽度为980px-->

<meta name="viewport" content="width=device-width, initial-scale=1">

</head>

<body>

<div class="Page_body"> <!-- 增加网页根div,设置网页铺满整个窗口 -->

<!-- 增加高度的样式设置 -->

<div class="container-fluid Body_Container">

<div class="row Body_Container"> <!-- 增加高度的样式设置 -->

<div class="col-sm-12 Body_Search">搜索区域</div>

<div class="col-sm-12 Body_Resource">资源列表区域</div>

<div class="col-sm-12 d-none d-sm-block Body_Page">翻页区域</div>

</div>

</div>

</div>

</body>

在代码3.26中,固定了搜索区域和翻页区域的高度,由资源区域铺满整个页面。设置资源列表区域的高度时用到了CSS的calc()函数,这个函数可以动态计算长度值,使用这个函数后,即使随意缩放浏览器窗口,资源区域也会铺满页面。以上代码的显示效果如图3.39所示。

图3.39 整体布局效果

提醒:例子中设置高度时使用的单位为px,而响应式布局一般提倡使用rem这个单位。rem是相对单位,是相对浏览器默认字号的比例,而浏览器默认字号会随着设备不同而有所区别,所以rem这个单位就可以间接地实现适应屏幕的效果。不过,在实际开发中,由于设置了<metaname="viewport"content="width=device-width,initial-scale=1">这个属性,使用px或rem单位的效果都差不多,而UI设计提供的单位一般都是px,使用rem单位的话还需要换算,所以个人还是喜欢用px作为单位。

模块布局

模块层是各模块分区的具体细节,模块层布局一般是组织页面控件等元素。对于这些控件,需要根据模块的div进行相对布局,不能全部以左上角为参考点。

模块布局由于是比较精细的布局,场景也是多种多样的,而且相对于整体布局,模块区域的布局一般不受屏幕大小的影响,除非手机网页和普通网页有不同的布局设计,所以不太推荐使用Bootstrap的栅格系统这些比较固定的布局模式,推荐的方法是根据不同的场景做不同的定制。使用HTML原生开发比较好一些,以搜索区域的模块布局为例,布局的思路和整体布局中设置高度的思路类似,固定一部分元素的尺寸,其他元素填充剩余的空白,其中CSS代码如代码3.28所示,HTML代码如代码3.29所示,效果如图3.40所示。

代码3.28 CSS设置

/* 设置搜索区域样式 */

.Body_Search {

height:50px;

background:gray;

padding:6px 10px;

padding-right:10px;

}

/* 设置搜索区域的输入框样式 */

.Body_Search_Input{

width: calc(100% - 100px - 10px);

margin-right: 10px;

float: left;

}

/* 设置搜索区域的搜索按钮输入框 */

.Body_Search_Button{

width: 100px;

}

代码3.29 HTML代码

<div class="col-sm-12 Body_Search">

<input class="form-control Body_Search_Input"><button class="btn btn-primary Body_Search_Button">搜索</button>

</div>


图3.40 搜索区域的布局效果

当然,对于比较复杂的结构(例如图3.37中的资源列表区域),可以把它再细化分层,使用一些响应式布局工具可能会方便一些,但是这些布局工具一定是项目初期已经确定好的JavaScript库、组件工具箱或框架中的内容。

适配性测试

无论前端开发经验多么丰富,我们都不可能在写前端代码的时候就能预见所有适配性的问题。所以需要在开发过程中,经常性地做适配性测试。

这里的适配性测试当然不是拿着几个显示器和手机来回尝试,而是使用浏览器自带的模拟器来做测试。以Chrome浏览器为例,打开调试工具(按F12键)后,单击toggle device toolbar按钮开启调试模式,如图3.41所示。开启调试模式后效果如图3.42所示。

图3.41 Chrome浏览器的调试工具

注意:在软件测试阶段还是推荐用真机测试为主,这里提供的模拟测试方法只作为补充使用,这样能很大程度上避免模拟器与真机的差异。

图3.42 开启调试模式的效果

浏览器兼容

兼容性指的是网页对不同浏览器的兼容。在3.2.2小节中已经提到了一般需要兼容的浏览器,本节介绍一些具体的解决思路。

由于浏览器内核(渲染引擎)和浏览器API有所区别,所以相同的网页运行在不同的浏览器上是有差别的。这些浏览器的差异,大部分已经被JavaScript库、组件工具箱及前端框架解决掉了。因此选用这些工具后,也意味着解决了大部分的浏览器兼容性问题,但是仍有一部分需要我们去解决。

造成浏览器发生兼容性问题主要有三部分原因,第一部分是浏览器内核(渲染引擎)的差异,其会让网页的显示效果有所差异。第二部分是JavaScript解析器的差异,虽然绝大部分浏览器的JavaScript解析器对JavaScript的语法支持没有区别(都支持ECMAScript5标准),但是在一些浏览器API的调用上是有区别的。第三部分是一些浏览器特有的限定,如微信中内嵌的浏览器,它劫持了播放器,不允许以一般的方式修改播放器样式,只能通过特定的方式修改。下面将对这三个部分展开介绍。

说明:最初的浏览器内核指的是渲染引擎和JavaScript解析器,后来JavaScript解析器被独立,因此现在都比较习惯直接称渲染引擎为浏览器内核。

1.浏览器内核(渲染引擎)

首先介绍比较流行的浏览器及其浏览器内核,如表3.1所示。其中国内的浏览器都倾向使用双内核,这大概是历史遗留问题,一些国内的交易网站的运行环境还必须是IE内核(如使用网银盾等产品的网站)。

表3.1 比较流行的浏览器及其内核

由于浏览器内核(渲染引擎)影响的是网页显示的效果,所以解决不同浏览器内核造成的影响一般在HTML和CSS这两部分上。HTML部分的问题相对少一些,除了IE 6~IE 10对一些HTML5的标签不识别外,基本上没有兼容性的问题。

CSS部分需要解决的问题多一些,虽然现在绝大多数浏览器都支持CSS3标准(除了IE),大部分的CSS属性设置上都是相同的,但是某些内核的私有属性是需要区分浏览器内核的。以设置圆角属性为例,如代码3.30所示。

注意:现在在CSS中设置圆角属性基本上不需要区分内核,使用border-radius即可。这里只是为了讲解方便,以一个比较常用且过去需要适配不同内核的属性为例。

代码3.30 CSS设置圆角属性

.class{

-webkit-border-radius: 8px; /*Blink、WebKit内核设置圆角*/

-moz-border-radius: 8px; /*Gecko内核设置圆角*/

border-radius: 8px; /*其他内核设置圆角*/

}

由于浏览器内核造成的显示效果差异,可以在开发过程中根据具体问题寻找对应的方法,这里不展开介绍。

2.JavaScript解析器

不同的JavaScript解析器带来的差异一般体现在浏览器API调用上,如代码3.31所示,其中调用浏览器全屏API需要根据浏览器进行区别。

代码3.31 JavaScript调用浏览器全屏接口

if(elem.webkitRequestFullScreen){

elem.webkitRequestFullScreen(); //设置Chrome、Safari等浏览器全屏

}else if(elem.mozRequestFullScreen){

elem.mozRequestFullScreen(); //设置Firefox等浏览器全屏

}else if(elem.requestFullScreen){

elem.requestFullscreen(); //设置其他浏览器全屏

}else{

//IE9以下等浏览器不支持全屏功能

}

JavaScript解析器相对于浏览器内核带来的兼容性问题相对较少,如果使用jQuery等JavaScript库的话,基本上不会遇到需要兼容JavaScript解析器的问题,以上的例子也是笔者到目前为止发现的少数几个需要解决的JavaScript解析器兼容性问题之一。

另外,由于JavaScript本身也在发展,新的语法只能在部分浏览器上被解析。例如,ECMAScript6标准的语法只有部分浏览器支持。不过,这类语法上的适配可以通过一些工具软件进行转换,例如,一些工具可以将ECMAScript6标准编写的JavaScript代码转换成低版本的ECMAScript5代码。

3.浏览器特有的限定

总有一些浏览器在某项功能上做了极其特别的处理,如在手机微信中嵌入的浏览器,它做了播放器劫持,浏览器会强行把播放器换成浏览器自己的播放器,开发者以普通的方式修改样式是不会生效的,只能通过特定的方式修改。

当然,手机浏览器劫持播放器是普遍存在的现象,但是解决的方式却不尽相同,有些甚至是不允许修改的。因此,对于浏览器特有的限定,只能根据不同的浏览器做不同的处理。对于这些特定的浏览器,可以通过JavaScript的navigator.userAgent变量获取浏览器信息来判断浏览器。

综上,浏览器的兼容性问题很难预见,只能在测试中发现。浏览器的兼容性的测试没有适配性测试方便,只能使用不同的浏览器做测试。不过,一般不需要将所有浏览器都测试一遍,以PC为例,使用Chrome、Safari和Firefox浏览器进行测试即可。其中Windows版的Safari浏览器是旧版,可能会造成一些测试上的困扰,不过Chrome浏览器的内核和Safari浏览器的内核比较相似,一般Chrome浏览器支持的内核在Safari浏览器里也会支持。

注意:解决浏览器兼容性问题除了顾及不同浏览器外,还要顾及相同浏览器的不同版本,如较新的Chrome浏览器提供了画中画功能,而旧版本的Chrome却没有这个功能。

本文给大家讲解的内容是大型网站架构的技术细节:前端架构,适配性和兼容性

  1. 下篇文章给大家讲解的内容是大型网站架构的技术细节:前端架构,模块化
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!

面试官:你知道移动端适配吗?

### 引言

在移动互联网时代,Web前端工程师面临的一大挑战就是如何在各类尺寸各异的设备上实现优质的用户体验。移动端适配,正是解决这一问题的核心技术手段。本文将深入浅出地阐述移动端适配的相关概念、策略以及实战技巧,让你从容应对面试官的犀利提问。

### 一、移动端适配的基础知识

**1.1 移动端设备屏幕多样性**

当前市场上的移动设备种类繁多,屏幕尺寸、分辨率和像素密度差异巨大。为了确保网站在各种设备上都能正常显示,移动端适配至关重要。

**1.2 视窗单位vw/vh与rem/em**

视窗单位vw/vh是相对于视口大小的百分比单位,可以帮助我们实现响应式布局:

```css

/* CSS 示例 */

.container {

width: 100vw;

height: 100vh;

}

```

相对单位rem/em则可以根据根元素字体大小自动缩放,便于整体布局的调控:

```css

html {

font-size: 62.5%; /* 将1rem设定为10px */

}

.container {

width: 30rem;

height: 20rem;

}

```

### 二、媒体查询与响应式设计

**2.1 CSS媒体查询**

媒体查询是实现响应式设计的关键工具,通过检测设备的特性来改变CSS样式:

```css

@media screen and (max-width: 768px) {

.container {

width: 100%;

}

}

```

**2.2 Bootstrap网格系统**

Bootstrap等前端框架提供的响应式网格系统简化了布局的适配工作,可根据屏幕大小自动分配列宽:

```html

<div class="container">

<div class="row">

<div class="col-sm-6 col-md-4">...</div>

<div class="col-sm-6 col-md-4">...</div>

<div class="col-sm-6 col-md-4">...</div>

</div>

</div>

```

### 三、移动端适配方案比较

**3.1 viewport元标签**

通过设置viewport元标签,可以控制页面在移动设备上的初始缩放级别和布局视口大小:

```html

<meta name="viewport" content="width=device-width, initial-scale=1.0">

```

**3.2 自适应方案:Flexible布局(Flex布局)**

Flex布局可以方便地处理元素在父容器内的排列与对齐,极大简化了复杂布局的适配过程:

```css

.container {

display: flex;

flex-wrap: wrap;

justify-content: space-around;

}

```

**3.3 移动设备像素比(devicePixelRatio)与高清屏适配**

针对高清屏设备,可以通过devicePixelRatio计算物理像素和CSS像素的比例,实现图片等资源的高清显示:

```javascript

let dpr = window.devicePixelRatio || 1;

let img = document.createElement('img');

img.src = `your-image-url?dpr=${dpr}`;

```

### 四、Vue.js移动端适配实战

**4.1 Vue.js中的响应式布局**

在Vue项目中,可以结合Vue的计算属性和侦听器实现动态调整布局:

```javascript

export default {

data() {

return {

screenWidth: 0

};

},

computed: {

containerWidth() {

return `${this.screenWidth}px`;

}

},

mounted() {

window.addEventListener('resize', this.handleResize);

},

beforeDestroy() {

window.removeEventListener('resize', this.handleResize);

},

methods: {

handleResize() {

this.screenWidth = document.documentElement.clientWidth;

}

}

}

```

**4.2 Vue移动端UI组件库的适配**

Vue生态中有许多成熟的移动端UI组件库(如Vuetify、Element-UI Mobile等),它们内置了完善的移动端适配方案,开发者可以直接使用。

### 结语

移动端适配不仅是Web前端开发者必备的专业技能,也是衡量一个优秀前端工程师的标准之一。无论面试官抛出何种问题,只要你掌握了以上所述的适配策略与方法,就能胸有成竹地给出专业解答,顺利通关面试环节。同时,持续关注行业新技术和最佳实践,不断提升自身在移动端适配领域的技术水平,才能在激烈的竞争中立于不败之地。

KEditor 4.16.2 维护版本已发布。此版本是一个维护版本,更新内容包括修复安全问题、修复浏览器兼容性问题、升级与 React 的集成,以及修复其他重要问题。

修复安全问题

修复了剪贴板插件中的安全漏洞 (CVE-2021-32809),该漏洞会引起出现滥用粘贴功能(使用格式错误的 HTML )的情况,进而导致将任意的 HTML 注入编辑器。

此外,在 Widget 插件中发现的另一个漏洞 (CVE-2021-32808) 容易导致出现执行 JavaScript 代码的情况,以及 Fake Objects 插件由于容易注入格式错误的 Fake Objects HTML (CVE-2021-37695),这也可能会导致执行 JavaScript 代码。

修复浏览器兼容性问题

此版本针对多款浏览器引入了多项错误修正和增强功能,确保跨平台兼容性,以提供最便捷的使用体验。

  • 修复在 Chrome 中显示空格键无效的问题。在删除两个连续空格的其中一个后,剩下的一个会直接以字符的形式 ( ) 显示,而非一个空格。最新的版本修复了这个问题,现在可以按预期运行。
  • 为所有支持的 Internet Explorer 版本引入了 CSS 选择器转义机制 (CSS.escape() polyfill)。此功能解决了表格元素(如 td、tr 或 th)的 id 以点开头会导致编辑器中出现 javascript 运行时错误的问题。另一个已解决的问题是,在 id 包含逗号的编辑器中无法拖放图像。新引入的机制完全符合最近的官方 HTML 规范。
  • 针对 Firefox 的错误修复。

升级与 React 的集成

与 React 的集成升级到了 2.0.0 版本,增加了对 React v17.x 的支持、对 React hooks 的支持,以及对 TypeScript 和类型的支持。详情点此查看。