CSS容易使人蒙圈的几个经典问题

开发 前端
本文摘自这一年来自己在工作中经历的几个比较好的CSS问题,这些CSS问题平时很少遇到,即使遇到后也不一定知道解决方案,即使知道解决方案也不一定知道产生的原理,同时也准备了2个JS问题一起看一下。

 [[312088]]

本文摘自这一年来自己在工作中经历的几个比较好的CSS问题(不一定复杂,但个人觉得都挺值得一说),这些CSS问题平时很少遇到,即使遇到后也不一定知道解决方案,即使知道解决方案也不一定知道产生的原理,同时也准备了2个JS问题(之前有整理过一篇较长的JS问题文章,在此不做推新)。本文会更新下去,希望帮到各位朋友。期待您的点赞,谢谢。

一、CSS篇

1.1 元素默认蓝色边框

input标签元素(如button、text 、areatext)的一些事件(如click、focus等),在很多浏览器下默认会有蓝色边框出现,如把一个普通button的background和border都设置为none后,触发点击后样式如下:

这是由元素默认的轮廓线产生的,这是浏览器的一种防护机制,起到突出元素的作用,把它干掉就行了,方法如下: 

  1. // 方法1:  
  2. outline: none / medium;  
  3. // 方法2:  
  4. outline-width: 0 

1.2 背景透明,文字不透明

我们通常是使用 opacity来做背景的透明化处理,该属性被所有浏览器支持,可以大胆使用,透明度从0.0(完全透明)到1.0(完全不透明),但该方法会使其所有子元素都透明,此时若只想让背景透明,其他不透明,则可以使用rgba处理背景: 

  1. background-color: rgba( red , green , blue , alpha ) 

其中这个alpha 即设置透明度,取值在0~1之间。该方法除IE9以下不可用外,其他浏览器均可用,看一下效果:

同理,我们也可以用这个方法把整个背景做透明了,即多写一个div作为modal层做透明处理,可以明显看到上面文字并未透明:

上述种效果代码如下: 

  1. // html  
  2. <section>  
  3.   <div class="item-pic">  
  4.     <header class="header1">  
  5.       <h4>你会微笑放手,说好不哭让我出新专辑</h4>  
  6.     </header>  
  7.   </div>  
  8.   <div class="item-pic">  
  9.     <header class="header2">  
  10.       <h4>你会微笑放手,说好不哭让我出新专辑</h4>  
  11.     </header>  
  12.   </div> 
  13.    <div class="item-pic">  
  14.     <div class="handle-opacity"> <!-- 透明罩 -->  
  15.       <header>  
  16.         <h4>你会微笑放手,说好不哭让我出新专辑</h4>  
  17.       </header>  
  18.     </div>  
  19.   </div>  
  20. </section>  
  21. <style lang="less">  
  22. .header1 {  
  23.   opacity: .6;  
  24.  
  25. .header2 {  
  26.   background-color: rgba(0, 0, 0, 0.45);  
  27.  
  28. .handle-opacity {  
  29.   position: absolute;  
  30.   width: 100%;  
  31.   height: 100%;  
  32.   background-color: rgba(255, 255, 255, 0.45);  
  33.   header {  
  34.     background-color: rgba(0, 0, 0, 0.45);  
  35.   }  
  36.  
  37. </style> 

1.3 div内置img元素,底部总有间距

用一个div包裹一个img,会出现img不能完全覆盖div空间,总会在底边留下一点空隙。

这种现象产生的原因是img是行内元素,浏览器为下行字符(如:g、y、j、p、q)留下的一些空间,这些字符是会比其他字符多占据底部一些空间(具体以当前字体大小有关),这种规则会影响行内元素img标签(其默认垂直对齐方式是依照基线来的,即vertical-align: baseline),同样行内元素都会和外部元素留这么一丢丢安全距离。上图右侧就是加了文字的效果,这样就更说明一切了。

现在我们知道这种现象主要是由于下行字符串保护机制和img是行内元素这两个因素导致的,那解决方案就从这两处入手,整理如下:

  1.  div设置font-size: 0或line-height: 0,进而行高为0;
  2.  img设置 vertical-align: top 或者 middle/,使其不再以默认基线为对齐方式;
  3.   mg设置 display:block,使其变成块级元素。

综上,个人认为方法3是最好用的,方法1不推荐使用。

1.4 元素自动填充上背景色

该现场多在表单输入等场景上会出现,初次看到确实很怪异,效果如图:

即当浏览器(chrome)给输入框自动填充内容后,也隐藏会自动给输入框带上背景(黄或灰蓝),该问题是由于chrome会默认给自动填充的input、select、textarea等加上:-webkit-autofill私有伪属性造成的,比较好的解决方案就是做样式覆盖,代码如下: 

  1. input:-webkit-autofill{  
  2.   box-shadow: 0 0 0px 1000px white inset !important;  
  3.  
  4. select:-webkit-autofill{  
  5.   box-shadow: 0 0 0px 1000px white inset !important;  
  6.  
  7. textarea:-webkit-autofill{  
  8.   box-shadow: 0 0 0px 1000px white inset !important;  

比较渣的办法是设置禁止自动填充,但还是别那样做了...

1.5 transform 基数值导致字体模糊

transform作为CSS3最为自豪的属性,已经成为了当前前端开发中不可或缺的方法,但它有个渲染的问题,即当元素设置有transform,且其值为基数或小数,同事其整体高度也有基数时,其内部文字会变模糊,如图:

上图上模糊状态下的,下图是修正过的,具体原因经查可能是因为transform变换会在浏览器上单独创建一个绘画层并重新进行渲染,在此渲染过程中也处理了周围的文字,如果高度为奇数的文字可能会存在半个像素的计算量,浏览器对这半个像素会进行优化渲染,所以边缘会出现模糊的情况。解决方案即:

  1.  不要给transform属性值设置基数和小时值;
  2.  调整整体元素高度不要为基数。

1.6 :last-child 和 :last-of-type

作为CSS常用伪类选择器,:last-child经常会被用到,但有时遇到极端情况,它会意外失效,让人摸不着头脑,例子如下:3个img标签包裹在card中,当前需求是使最后一张图的边框呈粉色,代码如下: 

  1. // html  
  2. <div class="card">  
  3.   <img  
  4.     v-for="(item,i) in pics"  
  5.     :key="i"  
  6.     :src="item"  
  7.   />  
  8. </div>  
  9. // css  
  10. <style lang="less">  
  11. .card {  
  12.   > img {  
  13.       width: 150px;  
  14.       margin-right: 10px;  
  15.       &:last-child {  
  16.         border: 5px solid pink;  
  17.       }  
  18.    }  
  19.  
  20. </style> 

同理用:last-of-type也能实现: 

  1. .card {  
  2.   > img {  
  3.       width: 150px;  
  4.       margin-right: 10px;  
  5.       &:last-of-type {  
  6.         border: 5px solid pink;  
  7.       }  
  8.    }  

效果如下:

现在要往img后加一个span,发现:last-child已失效: 

  1. // html  
  2. <div class="card">  
  3.   <img  
  4.     v-for="(item,i) in pics"  
  5.     :key="i"  
  6.     :src="item"  
  7.   />  
  8.   <span>next is ...</span>  
  9. </div>  
  10. // css  
  11. <style lang="less">  
  12. .card {  
  13.   > img {  
  14.       width: 150px;  
  15.       margin-right: 10px;  
  16.       &:last-child {  
  17.         border: 5px solid pink;  
  18.       }  
  19.    }  
  20.  
  21. </style> 

而此时:last-of-type依然没问题:

现在得出结论:

  1.  :last-child选取一群兄弟元素中的最后一个元素,且最后的这个元素必须是所声明的指定元素(注意2个条件);
  2.  :last-of-type选取一群兄弟元素中的最后一个指定类型的元素。

可知,:last-of-type更严谨一些,不容易产生意外bug,我更推荐使用它。同理适用于:nth-last-child(n)和:nth-last-of-type(n)

二、DOM篇

这部分我会叙述一些DOM操作遇到的一些容易被忽视的问题。

2.1 IOS日期显示问题

经常做H5移动端开发的朋友我想对这个问题肯定不陌生,那就是在部门IOS版本(IOS5及以下)中,对以“-”间隔的字符串时间格式的解析是不成功的,比如我们写了这么一个鸡肋时间格式适配器: 

  1. function DateFormat(date) {  
  2.   if(!date) return null;  
  3.   date = new Date(date);  
  4.   let Y = date.getFullYear();  
  5.   let M = (date.getMonth() >= 0 && date.getMonth() <= 8) ? `0${date.getMonth() + 1}` : `${date.getMonth() + 1}`;  
  6.   let D = (date.getDate() >= 0 && date.getDate() <= 9) ? `0${date.getDate()}`: `${date.getDate()}`;  
  7.   return `Y-M-D`  

此时如果在IOS5及以下版本的iphone下,传入 "2019-12-31"就会呈现出 NaN-NaN-NaN,而其他IOS版本及安卓系统都是没问题的。

针对上述问题,要做兼容适配,即把以"-"间隔的事件字符串替换成以"/"即可,同样是这个适配器,添加一段代码: 

  1. function DateFormat(date) {  
  2.   if(!date) return null;  
  3.   if(typeof date === 'string' &&  date.indexOf('T')!=-1 && date.indexOf('+')!=-1) {  
  4.     datedate = date.replace(/-/g, '/').replace('T',' ').substring(0,date.indexOf('.'))  
  5.   }  
  6.   date = new Date(date);  
  7.   let Y = date.getFullYear();  
  8.   let M = (date.getMonth() >= 0 && date.getMonth() <= 8) ? `0${date.getMonth() + 1}` : `${date.getMonth() + 1}`;  
  9.   let D = (date.getDate() >= 0 && date.getDate() <= 9) ? `0${date.getDate()}`: `${date.getDate()}`;  
  10.   return `Y-M-D`  

2.2 ENTER键使当前页刷新

这个真的很诡异的问题,当在一个表单中执行了ENTER键提交后,如果是打开新页面显示提交结果,则会发现当前表单页面也跟着刷新了,这种体验当然是很糟糕的。经查证,该问题的产生条件为:Form中只有一个input时,此时执行ENTER键会自动提交表单并刷新页面。解决方案也很粗暴,直接在input输入框附近写一个隐藏标签,这样就有2个input了,即避免了产生默认刷新的bug,实例如下: 

  1. <form>  
  2.   <input  
  3.     type="text"   
  4.     v-model.trim="searchText"   
  5.     placeholder="搜索您感兴趣的内容"  
  6.     @keyup.enter="goSearch"   
  7.   />  
  8.   <input  
  9.     id="hidden"   
  10.     type="text"   
  11.     style="display:none"   
  12.     @keyup.enter="goSearch"  
  13.   />  
  14. </form> 

终于在2020年到来前夕发了一篇比较赶的文章,结束我的2019之旅。本文会一直更新下去,如有不同见解和问题,请留言指出,期待您的点赞。最后祝您2020好运连连。 

 

责任编辑:庞桂玉 来源: 前端教程
相关推荐

2009-03-23 10:25:22

JavaOracle应用开发

2020-12-31 10:00:40

PoS终端终端安全网络攻击

2009-02-11 09:22:19

JavaJava开发Oracle应用

2018-02-25 12:19:02

2020-02-11 12:35:19

Kubernetes容器

2019-09-23 10:59:31

机器学习算法编程

2019-09-23 11:17:46

机器学习数据技术

2023-12-07 11:01:27

Python常用模块内置模块

2017-01-15 01:12:40

码农简历专业名词

2012-04-23 15:49:04

2012-04-25 10:18:49

jQuery

2021-06-29 15:52:03

PythonPOST

2023-06-15 13:59:00

人工智能智能家居

2020-05-21 11:29:58

复刻手机屏幕

2011-06-16 17:05:54

CSS

2014-12-29 10:11:44

Docke联合文件系统AUFS

2019-06-06 15:49:53

多线程iOS开发操作

2015-08-05 14:39:19

2010-09-03 08:52:38

CSS

2011-02-18 16:29:42

CSSWebHTML
点赞
收藏

51CTO技术栈公众号