Search K
Appearance
Appearance
掌握 熟悉 了解 一、CSS基础
盒模型都是由四个部分组成的,分别是margin、border、padding和content。 标准盒模型和IE盒模型的区别在于设置width和height时,所对应的范围不同: ● 标准盒模型的width和height属性的范围只包含了content, ● IE盒模型的width和height属性的范围包含了border、padding和content。 可以通过修改元素的box-sizing属性来改变元素的盒模型: ● box-sizeing: content-box表示标准盒模型(默认值) ● box-sizeing: border-box表示IE盒模型(怪异盒模型) 12. 为什么有时候⽤translate来改变位置⽽不是定位? translate 是 transform 属性的⼀个值。改变transform或opacity不会触发浏览器重新布局(reflow)或重绘(repaint),只会触发复合(compositions)。⽽改变绝对定位会触发重新布局,进⽽触发重绘和复合。transform使浏览器为元素创建⼀个 GPU 图层,但改变绝对定位会使⽤到 CPU。 因此translate()更⾼效,可以缩短平滑动画的绘制时间。 ⽽translate改变位置时,元素依然会占据其原始空间,绝对定位就不会发⽣这种情况。 13. li 与 li 之间有看不见的空白间隔是什么原因引起的?如何解决? 浏览器会把inline内联元素间的空白字符(空格、换行、Tab等)渲染成一个空格。为了美观,通常是一个li放在一行,这导致li换行后产生换行字符,它变成一个空格,占用了一个字符的宽度。 解决办法:
为li设置float:left。缺点:有些容器是不能设置浮动,如左右切换的焦点图等。
将所有li写在同一行。缺点:代码不美观。
将ul内的字符尺寸直接设为0,即font-size:0。缺点:ul中的其他字符尺寸也被设为0,需要额外重新设定其他字符尺寸,且在Safari浏览器依然会出现空白间隔。
消除ul的字符间隔letter-spacing:-8px。缺点:这也设置了li内的字符间隔,因此需要将li内的字符间隔设为默认letter-spacing:normal。
CSS3中有哪些新特性 CSS3新增了许多重要的特性:
新增选择器
盒模型相关
...(其余内容保持不变) 15. 替换元素的概念及计算规则 通过修改某个属性值呈现的内容就可以被替换的元素就称为"替换元素"。 替换元素除了内容可替换这一特性以外,还有以下特性: ● 内容的外观不受页面上的CSS的影响:用专业的话讲就是在样式表现在CSS作用域之外。如何更改替换元素本身的外观需要类似appearance属性,或者浏览器自身暴露的一些样式接口。 ● 有自己的尺寸:在Web中,很多替换元素在没有明确尺寸设定的情况下,其默认的尺寸(不包括边框)是300像素×150像素,如 ● 在很多CSS属性上有自己的一套表现规则:比较具有代表性的就是vertical-align属性,对于替换元素和非替换元素,vertical-align属性值的解释是不一样的。比方说vertical-align的默认值的baseline,很简单的属性值,基线之意,被定义为字符x的下边缘,而替换元素的基线却被硬生生定义成了元素的下边缘。 ● 所有的替换元素都是内联水平元素:也就是替换元素和替换元素、替换元素和文字都是可以在一行显示的。但是,替换元素默认的display值却是不一样的,有的是inline,有的是inline-block。 替换元素的尺寸从内而外分为三类: ● 固有尺寸: 指的是替换内容原本的尺寸。例如,图片、视频作为一个独立文件存在的时候,都是有着自己的宽度和高度的。 ● HTML尺寸: 只能通过HTML原生属性改变,这些HTML原生属性包括的width和height属性、的size属性。 ● CSS尺寸: 特指可以通过CSS的width和height或者max-width/min-width和max-height/min-height设置的尺寸,对应盒尺寸中的content box。 这三层结构的计算规则具体如下: (1)如果没有CSS尺寸和HTML尺寸,则使用固有尺寸作为最终的宽高。 (2)如果没有CSS尺寸,则使用HTML尺寸作为最终的宽高。 (3)如果有CSS尺寸,则最终尺寸由CSS属性决定。 (4)如果"固有尺寸"含有固有的宽高比例,同时仅设置了宽度或仅设置了高度,则元素依然按照固有的宽高比例显示。 (5)如果上面的条件都不符合,则最终宽度表现为300像素,高度为150像素。 (6)内联替换元素和块级替换元素使用上面同一套尺寸计算规则。 16. 常见的图片格式及使用场景 (1)BMP,是无损的、既支持索引色也支持直接色的点阵图。这种图片格式几乎没有对数据进行压缩,所以BMP格式的图片通常是较大的文件。 (2)GIF是无损的、采用索引色的点阵图。采用LZW压缩算法进行编码。文件小,是GIF格式的优点,同时,GIF格式还具有支持动画以及透明的优点。但是GIF格式仅支持8bit的索引色,所以GIF格式适用于对色彩要求不高同时需要文件体积较小的场景。 (3)JPEG是有损的、采用直接色的点阵图。JPEG的图片的优点是采用了直接色,得益于更丰富的色彩,JPEG非常适合用来存储照片,与GIF相比,JPEG不适合用来存储企业Logo、线框类的图。因为有损压缩会导致图片模糊,而直接色的选用,又会导致图片文件较GIF更大。 (4)PNG-8是无损的、使用索引色的点阵图。PNG是一种比较新的图片格式,PNG-8是非常好的GIF格式替代者,在可能的情况下,应该尽可能的使用PNG-8而不是GIF,因为在相同的图片效果下,PNG-8具有更小的文件体积。除此之外,PNG-8还支持透明度的调节,而GIF并不支持。除非需要动画的支持,否则没有理由使用GIF而不是PNG-8。 (5)PNG-24是无损的、使用直接色的点阵图。PNG-24的优点在于它压缩了图片的数据,使得同样效果的图片,PNG-24格式的文件大小要比BMP小得多。当然,PNG24的图片还是要比JPEG、GIF、PNG-8大得多。 (6)SVG是无损的矢量图。SVG是矢量图意味着SVG图片由直线和曲线以及绘制它们的方法组成。当放大SVG图片时,看到的还是线和曲线,而不会出现像素点。SVG图片在放大时,不会失真,所以它适合用来绘制Logo、Icon等。 (7)WebP是谷歌开发的一种新图片格式,WebP是同时支持有损和无损压缩的、使用直接色的点阵图。从名字就可以看出来它是为Web而生的,什么叫为Web而生呢?就是说相同质量的图片,WebP具有更小的文件体积。现在网站上充满了大量的图片,如果能够降低每一个图片的文件大小,那么将大大减少浏览器和服务器之间的数据传输量,进而降低访问延迟,提升访问体验。目前只有Chrome浏览器和Opera浏览器支持WebP格式,兼容性不太好。 ● 在无损压缩的情况下,相同质量的WebP图片,文件大小要比PNG小26%; ● 在有损压缩的情况下,具有相同图片精度的WebP图片,文件大小要比JPEG小25%~34%; ● WebP图片格式支持图片透明度,一个无损压缩的WebP图片,如果要支持透明度只需要22%的格外文件大小。 17. 对 CSSSprites 的理解 CSSSprites(精灵图),将一个页面涉及到的所有图片都包含到一张大图中去,然后利用CSS的 background-image,background-repeat,background-position属性的组合进行背景定位。 优点: ● 利用CSS Sprites能很好地减少网页的http请求,从而大大提高了页面的性能,这是CSS Sprites最大的优点; ● CSS Sprites能减少图片的字节,把3张图片合并成1张图片的字节总是小于这3张图片的字节总和。 缺点: ● 在图片合并时,要把多张图片有序的、合理的合并成一张图片,还要留好足够的空间,防止板块内出现不必要的背景。在宽屏及高分辨率下的自适应页面,如果背景不够宽,很容易出现背景断裂; ● CSSSprites在开发的时候相对来说有点麻烦,需要借助photoshop或其他工具来对每个背景单元测量其准确的位置。 ● 维护方面:CSS Sprites在维护的时候比较麻烦,页面背景有少许改动时,就要改这张合并的图片,无需改的地方尽量不要动,这样避免改动更多的CSS,如果在原来的地方放不下,又只能(最好)往下加图片,这样图片的字节就增加了,还要改动CSS。 18. 什么是物理像素,逻辑像素和像素密度,为什么在移动端开发时需要用到@3x, @2x这种图片? 以 iPhone XS 为例,当写 CSS 代码时,针对于单位 px,其宽度为 414px & 896px,也就是说当赋予一个 DIV元素宽度为 414px,这个 DIV 就会填满手机的宽度; 而如果有一把尺子来实际测量这部手机的物理像素,实际为 12422688 物理像素;经过计算可知,1242/414=3,也就是说,在单边上,一个逻辑像素=3个物理像素,就说这个屏幕的像素密度为 3,也就是常说的 3 倍屏。 对于图片来说,为了保证其不失真,1 个图片像素至少要对应一个物理像素,假如原始图片是 500300 像素,那么在 3 倍屏上就要放一个 1500900 像素的图片才能保证 1 个物理像素至少对应一个图片像素,才能不失真。 当然,也可以针对所有屏幕,都只提供最高清图片。虽然低密度屏幕用不到那么多图片像素,而且会因为下载多余的像素造成带宽浪费和下载延迟,但从结果上说能保证图片在所有屏幕上都不会失真。 还可以使用 CSS 媒体查询来判断不同的像素密度,从而选择不同的图片: my-image { background: (low.png); } @media only screen and (min-device-pixel-ratio: 1.5) { #my-image { background: (high.png); } } 19. margin 和 padding 的使用场景 ● 需要在border外侧添加空白,且空白处不需要背景(色)时,使用 margin; ● 需要在border内测添加空白,且空白处需要背景(色)时,使用 padding。 20. 对line-height 的理解及其赋值方式 (1)line-height的概念: ● line-height 指一行文本的高度,包含了字间距,实际上是下一行基线到上一行基线距离; ● 如果一个标签没有定义 height 属性,那么其最终表现的高度由 line-height 决定; ● 一个容器没有设置高度,那么撑开容器高度的是 line-height,而不是容器内的文本内容; ● 把 line-height 值设置为 height 一样大小的值可以实现单行文字的垂直居中; ● line-height 和 height 都能撑开一个高度; (2)line-height 的赋值方式: ● 带单位:px 是固定值,而 em 会参考父元素 font-size 值计算自身的行高 ● 纯数字:会把比例传递给后代。例如,父级行高为 1.5,子元素字体为 18px,则子元素行高为 1.5 * 18 = 27px ● 百分比:将计算后的值传递给后代 21. CSS 优化和提高性能的方法有哪些? 加载性能: (1)css压缩:将写好的css进行打包压缩,可以减小文件体积。 (2)css单一样式:当需要下边距和左边距的时候,很多时候会选择使用 margin:top 0 bottom 0;但margin-bottom:bottom;margin-left:left;执行效率会更高。 (3)减少使用@import,建议使用link,因为后者在页面加载时一起加载,前者是等待页面加载完成之后再进行加载。 选择器性能: (1)关键选择器(key selector)。选择器的最后面的部分为关键选择器(即用来匹配目标元素的部分)。CSS选择符是从右到左进行匹配的。当使用后代选择器的时候,浏览器会遍历所有子元素来确定是否是指定的元素等等; (2)如果规则拥有ID选择器作为其关键选择器,则不要为规则增加标签。过滤掉无关的规则(这样样式系统就不会浪费时间去匹配它们了)。 (3)避免使用通配规则,如{}计算次数惊人,只对需要用到的元素进行选择。 (4)尽量少的去对标签进行选择,而是用class。 (5)尽量少的去使用后代选择器,降低选择器的权重值。后代选择器的开销是最高的,尽量将选择器的深度降到最低,最高不要超过三层,更多的使用类来关联每一个标签元素。 (6)了解哪些属性是可以通过继承而来的,然后避免对这些属性重复指定规则。 渲染性能: (1)慎重使用高性能属性:浮动、定位。 (2)尽量减少页面重排、重绘。 (3)去除空规则:{}。空规则的产生原因一般来说是为了预留样式。去除这些空规则无疑能减少css文档体积。 (4)属性值为0时,不加单位。 (5)属性值为浮动小数0.**,可以省略小数点之前的0。 (6)标准化各种浏览器前缀:带浏览器前缀的在前。标准属性在后。 (7)不使用@import前缀,它会影响css的加载速度。 (8)选择器优化嵌套,尽量避免层级过深。 (9)css雪碧图,同一页面相近部分的小图标,方便使用,减少页面的请求次数,但是同时图片本身会变大,使用时,优劣考虑清楚,再使用。 (10)正确使用display的属性,由于display的作用,某些样式组合会无效,徒增样式体积的同时也影响解析性能。 (11)不滥用web字体。对于中文网站来说WebFonts可能很陌生,国外却很流行。web fonts通常体积庞大,而且一些浏览器在下载web fonts时会阻塞页面渲染损伤性能。 可维护性、健壮性: (1)将具有相同属性的样式抽离出来,整合并通过class在页面中进行使用,提高css的可维护性。 (2)样式与内容分离:将css代码定义到外部css中。 22. CSS预处理器/后处理器是什么?为什么要使用它们? 预处理器, 如:less,sass,stylus,用来预编译sass或者less,增加了css代码的复用性。层级,mixin, 变量,循环, 函数等对编写以及开发UI组件都极为方便。 后处理器, 如: postCss,通常是在完成的样式表中根据css规范处理css,让其更加有效。目前最常做的是给css属性添加浏览器私有前缀,实现跨浏览器兼容性的问题。 css预处理器为css增加一些编程特性,无需考虑浏览器的兼容问题,可以在CSS中使用变量,简单的逻辑程序,函数等在编程语言中的一些基本的性能,可以让css更加的简洁,增加适应性以及可读性,可维护性等。 其它css预处理器语言:Sass(Scss), Less, Stylus, Turbine, Swithch css, CSS Cacheer, DT Css。 使用原因: ● 结构清晰, 便于扩展 ● 可以很方便的屏蔽浏览器私有语法的差异 ● 可以轻松实现多重继承 ● 完美的兼容了CSS代码,可以应用到老项目中 23. ::before 和 :after 的双冒号和单冒号有什么区别? (1)冒号(:)用于CSS3伪类,双冒号(::)用于CSS3伪元素。 (2)::before就是以一个子元素的存在,定义在元素主体内容之前的一个伪元素。并不存在于dom之中,只存在在页面之中。 注意: :before 和 :after 这两个伪元素,是在CSS2.1里新出现的。起初,伪元素的前缀使用的是单冒号语法,但随着Web的进化,在CSS3的规范里,伪元素的语法被修改成使用双冒号,成为::before、::after。 24. display:inline-block 什么时候会显示间隙? ● 有空格时会有间隙,可以删除空格解决; ● margin正值时,可以让margin使用负值解决; ● 使用font-size时,可通过设置font-size:0、letter-spacing、word-spacing解决; 25. 单行、多行文本溢出隐藏 ● 单行文本溢出 overflow: hidden; // 溢出隐藏 text-overflow: ellipsis; // 溢出用省略号显示 white-space: nowrap; // 规定段落中的文本不进行换行 ● 多行文本溢出 overflow: hidden; // 溢出隐藏 text-overflow: ellipsis; // 溢出用省略号显示 display:-webkit-box; // 作为弹性伸缩盒子模型显示。 -webkit-box-orient:vertical; // 设置伸缩盒子的子元素排列方式:从上到下垂直排列 -webkit-line-clamp:3; // 显示的行数 注意:由于上面的三个属性都是 CSS3 的属性,没有浏览器可以兼容,所以要在前面加一个-webkit- 来兼容一部分浏览器。 26. Sass、Less 是什么?为什么要使用他们? 他们都是 CSS 预处理器,是 CSS 上的一种抽象层。他们是一种特殊的语法/语言编译成 CSS。 例如 Less 是一种动态样式语言,将 CSS 赋予了动态语言的特性,如变量,继承,运算, 函数,LESS 既可以在客户端上运行 (支持 IE 6+, Webkit, Firefox),也可以在服务端运行 (借助 Node.js)。 为什么要使用它们? ● 结构清晰,便于扩展。 可以方便地屏蔽浏览器私有语法差异。封装对浏览器语法差异的重复处理, 减少无意义的机械劳动。 ● 可以轻松实现多重继承。 完全兼容 CSS 代码,可以方便地应用到老项目中。LESS 只是在 CSS 语法上做了扩展,所以老的 CSS 代码也可以与 LESS 代码一同编译。 27. 对媒体查询的理解? 媒体查询由⼀个可选的媒体类型和零个或多个使⽤媒体功能的限制了样式表范围的表达式组成,例如宽度、⾼度和颜⾊。媒体查询,添加⾃CSS3,允许内容的呈现针对⼀个特定范围的输出设备⽽进⾏裁剪,⽽不必改变内容本身,适合web⽹⻚应对不同型号的设备⽽做出对应的响应适配。 媒体查询包含⼀个可选的媒体类型和满⾜CSS3规范的条件下,包含零个或多个表达式,这些表达式描述了媒体特征,最终会被解析为true或false。如果媒体查询中指定的媒体类型匹配展示⽂档所使⽤的设备类型,并且所有的表达式的值都是true,那么该媒体查询的结果为true。那么媒体查询内的样式将会⽣效。
<!-- link元素中的CSS媒体查询 -->
<link rel="stylesheet" media="(max-width: 800px)" href="example.css" />
<!-- 样式表中的CSS媒体查询 -->
<style>
@media (max-width: 600px) {
.facet_sidebar {
display: none;
}
}
</style>
简单来说,使用 @media 查询,可以针对不同的媒体类型定义不同的样式。@media 可以针对不同的屏幕尺寸设置不同的样式,特别是需要设置设计响应式的页面,@media 是非常有用的。当重置浏览器大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面。 28. 对 CSS 工程化的理解 CSS 工程化是为了解决以下问题:
.left { position: absolute; width: 100px; height: 100px; background: tomato; }
.right { position: absolute; top: 0; right: 0; width: 200px; height: 100px; background: gold; }
.center { margin-left: 100px; margin-right: 200px; height: 100px; background: lightgreen; } ● 利用flex布局,左右两栏设置固定大小,中间一栏设置为flex:1。 .outer { display: flex; height: 100px; }
.left { width: 100px; background: tomato; }
.right { width: 100px; background: gold; }
.center { flex: 1; background: lightgreen; } ● 利用浮动,左右两栏设置固定大小,并设置对应方向的浮动。中间一栏设置左右两个方向的margin值,注意这种方式,中间一栏必须放到最后: .outer { height: 100px; }
.left { float: left; width: 100px; height: 100px; background: tomato; }
.right { float: right; width: 200px; height: 100px; background: gold; }
.center { height: 100px; margin-left: 100px; margin-right: 200px; background: lightgreen; } ● 圣杯布局,利用浮动和负边距来实现。父级元素设置左右的 padding,三列均设置向左浮动,中间一列放在最前面,宽度设置为父级元素的宽度,因此后面两列都被挤到了下一行,通过设置 margin 负值将其移动到上一行,再利用相对定位,定位到两边。 .outer { height: 100px; padding-left: 100px; padding-right: 200px; }
.left { position: relative; left: -100px;
float: left; margin-left: -100%;
width: 100px; height: 100px; background: tomato; }
.right { position: relative; left: 200px;
float: right; margin-left: -200px;
width: 200px; height: 100px; background: gold; }
.center { float: left;
width: 100%; height: 100px; background: lightgreen; } ● 双飞翼布局,双飞翼布局相对于圣杯布局来说,左右位置的保留是通过中间列的 margin 值来实现的,而不是通过父元素的 padding 来实现的。本质上来说,也是通过浮动和外边距负值来实现的。 .outer { height: 100px; }
.left { float: left; margin-left: -100%;
width: 100px; height: 100px; background: tomato; }
.right { float: left; margin-left: -200px;
width: 200px; height: 100px; background: gold; }
.wrapper { float: left;
width: 100%; height: 100px; background: lightgreen; }
.center { margin-left: 100px; margin-right: 200px; height: 100px; } 5. 水平垂直居中的实现 ● 利用绝对定位,先将元素的左上角通过top:50%和left:50%定位到页面的中心,然后再通过translate来调整元素的中心点到页面的中心。该方法需要考虑浏览器兼容问题。 .parent {
position: relative; } .child {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%); } ● 利用绝对定位,设置四个方向的值都为0,并将margin设置为auto,由于宽高固定,因此对应方向实现平分,可以实现水平和垂直方向上的居中。该方法适用于盒子有宽高的情况: .parent { position: relative; }
.child { position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; } ● 利用绝对定位,先将元素的左上角通过top:50%和left:50%定位到页面的中心,然后再通过margin负值来调整元素的中心点到页面的中心。该方法适用于盒子宽高已知的情况 .parent { position: relative; }
.child { position: absolute; top: 50%; left: 50%; margin-top: -50px; /* 自身 height 的一半 / margin-left: -50px; / 自身 width 的一半 */ } ● 使用flex布局,通过align-items:center和justify-content:center设置容器的垂直和水平方向上为居中对齐,然后它的子元素也可以实现垂直和水平的居中。该方法要考虑兼容的问题,该方法在移动端用的较多: .parent { display: flex; justify-content:center; align-items:center; } 6. 如何根据设计稿进行移动端适配? 移动端适配主要有两个维度: ● 适配不同像素密度, 针对不同的像素密度,使用 CSS 媒体查询,选择不同精度的图片,以保证图片不会失真; ● 适配不同屏幕大小, 由于不同的屏幕有着不同的逻辑像素大小,所以如果直接使用 px 作为开发单位,会使得开发的页面在某一款手机上可以准确显示,但是在另一款手机上就会失真。为了适配不同屏幕的大小,应按照比例来还原设计稿的内容。 为了能让页面的尺寸自适应,可以使用 rem,em,vw,vh 等相对单位。
/* 例如,在媒体查询中设置不同屏幕尺寸下的样式 / @media (max-width: 768px) { / 添加针对小屏幕的样式 */ }
@media (min-width: 768px) and (max-width: 1024px) { /* 添加针对中等屏幕的样式 */ }
● fixed: 元素的定位是相对于 window (或者 iframe)边界的,和其他元素没有关系。但是它具有破坏性,会导致其他元素位置的变化。
● absolute: 元素的定位相对于前两者要复杂许多。如果为 absolute 设置了 top、left,浏览器会根据什么去确定它的纵向和横向的偏移量呢?答案是浏览器会递归查找该元素的所有父元素,如果找到一个设置了position:relative/absolute/fixed的元素,就以该元素为基准定位,如果没找到,就以浏览器边界定位。如下两个图所示:
div {
width: 0;
height: 0;
border-top: 50px solid red;
border-right: 50px solid transparent;
border-left: 50px solid transparent; } (2)三角2
div { width: 0; height: 0; border-bottom: 50px solid red; border-right: 50px solid transparent; border-left: 50px solid transparent; } (3)三角3
div { width: 0; height: 0; border-left: 50px solid red; border-top: 50px solid transparent; border-bottom: 50px solid transparent; }
(4)三角4
div { width: 0; height: 0; border-right: 50px solid red; border-top: 50px solid transparent; border-bottom: 50px solid transparent; } (5)三角5
div { width: 0; height: 0; border-top: 100px solid red; border-right: 100px solid transparent; } 还有很多,就不一一实现了,总体的原则就是通过上下左右边框来控制三角形的方向,用边框的宽度比来控制三角形的角度。 2. 实现一个扇形 用CSS实现扇形的思路和三角形基本一致,就是多了一个圆角的样式,实现一个90°的扇形: div{ border: 100px solid transparent; width: 0; heigt: 0; border-radius: 100px; border-top-color: red; }
这样就能缩放到原来的0.5倍,如果是1px那么就会变成0.5px。viewport只针对于移动端,只在移动端上才能看到效果 5. 设置小于12px的字体 在谷歌下css设置字体大小为12px及以下时,显示都是一样大小,都是默认12px。 解决办法: ● 使用Webkit的内核的-webkit-text-size-adjust的私有CSS属性来解决,只要加了-webkit-text-size-adjust:none;字体大小就不受限制了。但是chrome更新到27版本之后就不可以用了。所以高版本chrome谷歌浏览器已经不再支持-webkit-text-size-adjust样式,所以要使用时候慎用。 ● 使用css3的transform缩放属性-webkit-transform:scale(0.5); 注意-webkit-transform:scale(0.75);收缩的是整个元素的大小,这时候,如果是内联元素,必须要将内联元素转换成块元素,可以使用display:block/inline-block/...; ● 使用图片:如果是内容固定不变情况下,使用将小于12px文字内容切出做图片,这样不影响兼容也不影响美观。 6. 如何解决 1px 问题? 1px 问题指的是:在一些 Retina屏幕 的机型上,移动端页面的 1px 会变得很粗,呈现出不止 1px 的效果。原因很简单——CSS 中的 1px 并不能和移动设备上的 1px 划等号。它们之间的比例关系有一个专门的属性来描述: window.devicePixelRatio = 设备的物理像素 / CSS像素。 打开 Chrome 浏览器,启动移动端调试模式,在控制台去输出这个 devicePixelRatio 的值。这里选中 iPhone6/7/8 这系列的机型,输出的结果就是2: 这就意味着设置的 1px CSS 像素,在这个设备上实际会用 2 个物理像素单元来进行渲染,所以实际看到的一定会比 1px 粗一些。 解决1px 问题的三种思路: 思路一:直接写 0.5px 如果之前 1px 的样式这样写: css 复制代码border:1px solid #333 可以先在 JS 中拿到 window.devicePixelRatio 的值,然后把这个值通过 JSX 或者模板语法给到 CSS 的 data 里,达到这样的效果(这里用 JSX 语法做示范):
然后就可以在 CSS 中用属性选择器来命中 devicePixelRatio 为某一值的情况,比如说这里尝试命中 devicePixelRatio 为2的情况: #container[data-device="2"] { border:0.5px solid #333 } 直接把 1px 改成 1/devicePixelRatio 后的值,这是目前为止最简单的一种方法。这种方法的缺陷在于兼容性不行,IOS 系统需要8及以上的版本,安卓系统则直接不兼容。 思路二:伪元素先放大后缩小 这个方法的可行性会更高,兼容性也更好。唯一的缺点是代码会变多。 思路是先放大、后缩小:在目标元素的后面追加一个 ::after 伪元素,让这个元素布局为 absolute 之后、整个伸展开铺在目标元素上,然后把它的宽和高都设置为目标元素的两倍,border值设为 1px。接着借助 CSS 动画特效中的放缩能力,把整个伪元素缩小为原来的 50%。此时,伪元素的宽高刚好可以和原有的目标元素对齐,而 border 也缩小为了 1px 的二分之一,间接地实现了 0.5px 的效果。 代码如下: #container[data-device="2"] { position: relative; } #container[data-device="2"]::after{ position:absolute; top: 0; left: 0; width: 200%; height: 200%; content:""; transform: scale(0.5); transform-origin: left top; box-sizing: border-box; border: 1px solid #333; } } 思路三:viewport 缩放来解决 这个思路就是对 meta 标签里几个关键属性下手: 这里针对像素比为2的页面,把整个页面缩放为了原来的1/2大小。这样,本来占用2个物理像素的 1px 样式,现在占用的就是标准的一个物理像素。根据像素比的不同,这个缩放比例可以被计算为不同的值,用 js 代码实现如下: const scale = 1 / window.devicePixelRatio; // 这里 metaEl 指的是 meta 标签对应的 Dom metaEl.setAttribute('content', `width=device-width, user-scalable=no, initial-scale=${scale}, maximum-scale=${scale}, minimum-scale=${scale}`); 这样解决了,但这样做的副作用也很大,整个页面被缩放了。这时 1px 已经被处理成物理像素大小,这样的大小在手机上显示边框很合适。但是,一些原本不需要被缩小的内容,比如文字、图片等,也被无差别缩小掉了。