前言

我想在我们开始的学CSS语法的时候,都是从以下的流程开始的:

1、写一个CSS类选择器:

.my-class {
}

2、往选择器里填充CSS语法:

.my-class {
display flex;
flex-direction row
}

3、在 HTML的 class 属性中写上选择器名:

div class=”my-class”div

以此来将CSS的效果应用到HTML上。

在很长的一段时间里,我也一直都是这么写的。但是慢慢地,我感觉到越来越别扭,却说不出是哪里不对。到后来我接触到了像bootstrap之类的UI库,这种UI库最大的特点就是将每一个CSS类都写成了一个CSS选择器的方式,比如:.text-center 里只有一个CSS语法——text-align center; 起初我以为这种啰啰嗦嗦的方式会让我写起来非常麻烦,但我却发现这种方式比起以往的写法,给我带来了相当大的便利,我也想明白了以往的CSS写法别扭在什么地方。我将在本文中描述我的感受。

语义类CSS和功能类CSS

语义类和功能类两者其实是CSS的两种写法。

我在前言中说到的,将CSS语法写在CSS选择器中,再将选择器名写在HTML的class属性中,这种写法就是语义类,也有叫做内嵌类的。而功能类就是像bootstrap之类的UI库的写法,特点是通过某种方式直接在HTML的class类名中写上代表CSS的某个语法的名字,来实现少数的CSS效果。比如

div class=”text-center”
这里应用的CSS类选择器text-center,其实际内容只有一个CSS语法text-align center;
div

这两种方法,可能也有别的名字,但这不重要,重要的是我们知道它们代表什么,在本文中,就叫语义类和功能类吧。

我们可以很明显地看到两种写法的迥然不同之处。语义化的写法提倡将一系列的CSS语法写在选择器里,再给选择器取一个合适的名字,应用到HTML上,以达到语义化的效果。好处是可以根据类名来达到重用(重点),如:有一个CSS类,叫 .btn,我在里面定义按钮的样式效果,之后我就可以给所有的 button标签应用上该 .btn类,来达到同样的按钮效果。

功能类的语法则是完全摒弃了CSS类名的语义,在这里,CSS的类名只用来表示实现的功能,而不表示含义。比如CSS类名 .text-center,这个CSS类名如果只从名字上来看是看不出任何语义的,但是它可以一目了然地看出该CSS类的实现是:text-align center; 达到居中效果,且也只有这一个效果。其特点在于,CSS类名就是其实现。那么,对于每一个CSS的实现,就必须有一个CSS类名来对应,如此一来,CSS庞大的实现语句也一定会造就庞大的CSS功能类,人工是不可能在项目中先写好需要用到的CSS类名再去开发的。所以,引用第三方的UI库就是使用功能类的先决条件。

如果是从上面两者的介绍来看,语义类的优点是很明显的:类名简单易懂,可重用,规范容易统一。再看功能类,似乎看不出优点,而且让人觉得:写起来啰里啰唆,对于复杂的效果类名很长,不同元素的相同效果无法重用。功能类简直是看不到什么好处。

既然两者的优劣这么明显,那我又是为何从语义类优先的写法转变到功能类优先的写法呢?

为何从语义类优先转变到功能类优先

当我大量的使用语义类开发的时候,我发现我很多地方都用上了style语法,就是直接修改元素的style属性:

div class=”text-center”
语义类
div
div class=”text-center” style=”text-align text;”
语义类并且,使用了style语法。
div

因为当我为一个元素编写样式的时候,是无法断定这个样式是否能够完美的应用在其他需要的元素上,比如像div、span、main等其他布局用途的元素。按钮等功能元素不在此列。

原因之一是使用HTML语法来编写同一个页面可以有多种方式,不同方式所能搭配的CSS语句不同。可以这么说,只要不是两个完全一摸一样的页面,其样式上就会有差别。页面布局的表现,是建立在多个元素的搭配下的。比如我要编写一个容器的左右布局,至少需要三个元素,其中一个元素表示容器,一个元素表示容器内的左侧内容,一个元素表示容器内的右侧内容。更复杂的布局,需要的元素组合也就更多,当元素内元素一多,为了容器内多个元素的统一操作,也就需要另一个容器将这多个需要统一操作的元素包裹起来,即容器内的容器元素。

CSS只能够应用在元素上,使应用的元素的样式发生变化,flex,grid语句也能够使元素内部的结构发生变化。不过CSS仍然只能美化它应用的元素,不能美化它的自己的子级元素。所以,如果要让CSS达到美化一整个容器的效果,就需要让CSS应用到每一个容器内元素上。打个比方,有如下布局:

div class=”container”
div class=”left-side”
左侧内容
div
div class=”right-side”
右侧内容
div
div

如果我只实现了container类的CSS美化效果,只会美化container。为了使container内部的left-side和right-side也美化,我也就需要单独美化这两者。然而,容器内左侧和右侧的美化效果如何,完全取决于它们的容器是什么。如果它们的容器是一个导航栏,那么容器内左侧和右侧要怎么美化;如果容器是个列表框,那么容器内左侧和右侧要怎么美化。由此可见,单单一个container类是无法重用的,很自然的,我们必须细分出导航栏的nav类和列表框的list类。我们的container变成了两个截然不同的CSS类。

div class=”nav”
……
div
div class=”list”
……
div

导航栏在大多数项目中样式都比较统一,如果我们分析导航栏的样式,就会知道,导航栏的一系列CSS类只能应用在导航栏中,完全无法应用到其他类型的布局中。这也是由于将CSS应用到容器和它的各个子元素中决定的,容器中的子元素,使用什么美化语句,需要视容器元素而定。这样一来,如果我要将nav应用到列表框,就需要将导航栏容器以及它的子级CSS类都逐一应用到列表框里。但是这种逐一应用无法实现的原因在于,两者的元素布局不同,只要两者的容器和子级不是完全一样,就无法逐一应用CSS类。

CSS语义类名只能完全服务于它的元素。

按照这个理论,我们也就能解释为什么按钮可以做到CSS类名重用,像bootstrap中的btn类名应用到所有按钮中,因为我们通常只使用按钮这个元素本身,不会给他再嵌套进其他元素。同理,像A标签也一样。但是如果我们尝试给按钮或者A标签中添加其他子元素,就能够看到它们变得怪异。

在我认识到这一点之前,我仍然在大量使用语义类CSS。很快,在重用CSS类到其他元素的时候我就遇到了怪异的情况:元素的美化效果不完全。这个时候为了调整样式,要么修改应用的CSS类,但这样一来,原先的元素的效果就会遭到破坏。要么多写一个CSS类,单独用来调整元素的效果,但是CSS语句的优先级是不可控的。所以为了不影响原先元素,为了可控,为了方便,我就直接写成了style语句。这种方式让HTML变得奇丑无比——页面上时不时就会冒出来style的写法。

很常见的一种情况就是一个元素,只需要一句CSS语句。我经常遇到一个元素我只需要调整它内部的文本位置,靠左靠右还是居中,调整一些内边距外边距。这种细微的调整,如果写成CSS类,也只能在这个类上应用。就算有其他的类,也需要相似的效果,但是效果的数值不同,就不能够应用这个类,那我就不得不再写一个给这个元素使用的类。

这种情况真的太常见了,如果给每个元素都写一个类,将造成维护上的困难,调整样式的时候,我不得不在HTML和CSS之间来回的切换页面,如果CSS种有伪类等变体语法,维护起来也更加困难——我需要先找出这个类相关的所有类。因为CSS的同一种页面效果实现不只有一种途径,而且不同的实现途径之间是不能够兼容写法的。比如,我要让div下的元素靠右,有好几种写法,如果div是flex布局或者是grid布局,都能实现靠右的效果,但是其子级的实现却会变得大不相同。所以,当我编写其子级的时候,经常不得不先去看它的父类的实现。

所以当后来我接触到了bootstrap中的功能类时,我想到,为什么不把语义类里的实现展开到HTML的class属性里呢。我便开始了功能类优先的写法。

功能类优先有何不同

这种写法的重点的是优先这两个字,而不是完全的追求功能类写法。在上文中我描述到,在使用语义类经常遇到预先编写的语义类不满足新的元素的情况,而参杂了语义类以外的写法。这种情况下,这个预先编写好的类如果不能够达到重用的效果,那么是否使用语义类写法也就无妨了。所以我将大量语义类的转变为功能类的写法,其效果也是很明显的,它大量减少了CSS文件的数量,HTML的样式实现也更加直观——因为直接写在了class上了,也不需要反复的切换文件去查找该类的实现。最重要的一点是,完全消除了style的写法,代码变得风格统一且相对美观。

例子如下:

figure class=flex rounded p-8 figure

上述的例子中的class含义可能难以理解,它们是功能类的写法,直接理解为CSS的实现语句会容易一点,如:flex就是display flex; p-8就是padding 8px; rounded就是border-radius .75rem; 当然,具体的数据跟含义依赖于你所引用的三方库的实现。

这种写法,一开始我跟很多第一次接触到功能类写法的人一样,很不理解,认为会给我增加代码数,且class类名变得很长会难以维护,但是当我实际使用后,我发现我的顾虑是多余的。首先的是功能类的写法提供了更少的CSS文件——通常指需要一个全局CSS文件;更少的字母数——如text-center代表align-text center;;更加直观的实现——所有的实现都直接写在class的属性值中。

我们上面论述到CSS语义类的重用是很艰难的,对着这些无法重用的CSS类,完全可以写成功能类写法,以规避其短处。像容器元素以及子级的元素,因为HTML的嵌套结构的限制,使得CSS类必须服务于这种嵌套,无法重用,那么就干脆不考虑重用这一块,全部展开成功能类好了。

当然,对于那些真正能够达到重用效果的CSS,使用语义类写法还是非常推荐的,尽管这种情况非常稀少。两者择其优之,杂用语义和功能,功能类的写法会更多,所以叫功能类优先。

重点在于要理解“优先”这两个字。

那么,不好用语义类的写法应该使用在什么地方呢?

语义类就不用了吗

语义类写法应当应用在能够充分发挥其重用、于HTML结构无关的地方。充分发挥重用,在于我将语义类应用到元素上后,不需要再写其他的CSS语句来进行调整。如果不能够重用,那还不如写功能类,以消除CSS文件。HTML元素的结构不同会影响到CSS的表现,使其重用功能受到影响,所以一个稳定的元素是应用语义类的前提。

在以上两个前提下,最合适应用的地方就是全局的设置和button类的设置。

全局的设置其实和重用无关也和元素结构无关,在全局的CSS文件里写上root属性可以方便地调整主题,也可以对HTML元素做出默认的设置,如默认消除body的margin。对于button元素,在于通常它是最小的单独使用元素单位,即与其他结构无关,不管在哪种结构中其样式都是固定的少数几种,最小单位是说它通常不会再嵌套其他的元素了。这两个特点使得button这种元素的性质十分稳定,语义类的写法非常合适于它。关于它的CSS类就可以写在全局的CSS文件中,达到全局的重用。然而这种类型的元素是少数。

常见问答

问:功能类优先的写法不会让人难以理解吗?

答:如果是说功能类在元素上展开了大量的类使得class属性值很长,那么是不用担心的。首先,你能够使用多少功能类,完全取决于你能够使用多少种原生的CSS语句,所以你完全不可能使用你不理解的功能类。如果担心使用功能类使得class属性值很长,请试想一点,难道将这些属性写在CSS类里,要写的字数就会变少了吗?功能类,不过是将原本在CSS类中的内容搬到的class属性中,该写多少还是会写多少。甚至是由于第三方库的优秀支持,使功能类的类名更加短小,在代码的编写上只会比语义类更方便。

问:多个功能类在class属性中的值太长,会不会使HTML难以阅读?

答:我强烈建议你试用功能类,这会让你更容易理解功能类的写法和阅读比起语义里更方便。当我调试语义类的时候,在开发人员工具(F12)中,我们会走以下流程:找到我们要调试的元素——找到它的类名——在开发人员工具栏中找到类名的实现——查看实现语句。在这个过程中,我们其实只关注开始的元素和结尾的实现语句,中间的流程可以说使因为语义类的写法而不得已存在的。如果我们使用功能为,这个流程就会变成:找到我们要调试的元素——查看class属性值。由于功能类的特性,当我们查看功能类的特性时也就是在查看其实现,完全省略了中间不必要的过程,只会更方便。如果你担心class属性值过长,那么只需要交给你的编辑器就行了,就像是应对你的JS代码,有各种lint工具来为你做这些事。

问:是否功能类一定要使用第三方UI库?

答:如果你的项目里对样式的要求不高不复杂,那么完全不需要任何第三方库,就算写成语义类也是可以的。如果项目的要求的样式复杂,使用第三方UI库来写功能类优先写法是更明智的选择。毕竟你一定不想把每个常用功能都实现一遍。

问:有推荐的第三方UI库吗?

答:tailwindcss

为什么我在css里使用功能类优先的更多相关文章

  1. CSS属性、伪类选择器,CSS3选择器

    CSS1时IE6是部分支持,伟大的IE6!CSS2时IE6部分支持,伟大的IE6依旧是部分支持!CCS3盛行CSS4也已经提上日程的现在,IE6完全不支持.IE6你该走了,我们会永远记住你的功绩的!I ...

  2. 关于解决asp.net mvc网站页面Banner图片即时更换css里背景图片url相对路径问题的新方案

    最近在网站首页上想将Banner壁纸给做到后台上传随时更改的效果.遇到问题便是:将上传的图片路径动态添加到首页css代码中,结果尝试了网上提供的思路,更改相对路径,换为url中“../../Conte ...

  3. ASP.NET MVC 4 RC的JS/CSS打包压缩功能 (转载)

    ASP.NET MVC 4 RC的JS/CSS打包压缩功能 打包(Bundling)及压缩(Minification)指的是将多个js文件或css文件打包成单一文件并压缩的做法,如此可减少浏览器需下载 ...

  4. CSS里的pointer-events属性

    现代浏览器里CSS的职责范围和JavaScript的越来越模糊分不清.比如CSS里-webkit-touch-callout属性在iOS里能禁止当用户点击时弹出气泡框.而本文要说的pointer-ev ...

  5. 【socket】Socket的三个功能类TCPClient、TCPListener 和 UDPClient

    Socket的三个功能类TCPClient.TCPListener 和 UDPClient (转) 应用程序可以通过 TCPClient.TCPListener 和 UDPClient 类使用传输控制 ...

  6. php之框架增加日志记录功能类

    <?php /* 思路:给定文件,写入读取(fopen ,fwrite……) 如果大于1M 则重写备份 传给一个内容, 判断大小,如果大于1M,备份 小于则写入 */ class Log{ // ...

  7. CSS里的 no-repeat 是什么意思

    CSS里的 no-repeat是针对背景图片来说的.当你设置了no-repeat这个属性后,你的背景图片将不会被重复,再换一种说法,你在网站上所看到的背景图片就是你所添加的图片, 不会出现平铺或者重复 ...

  8. 【演示】在CSS里用calc进行计算

    请阅读 在CSS里用calc进行计算   下面的元素的width,padding,margin都使用了CSS calc进行计算. 简单计算: 100% – 100px 这是经过简单计算的元素宽度 复杂 ...

  9. 使用CSS里的user-select属性控制用户在页面上选中的内容

    CSS里的user-select属性用来禁止用户用鼠标在页面上选中文字.图片等,也就是,让页面内容不可选.也可以只允许用户选中文字,或者全部都放开,用户可以同时选中文字.还包括文本里的图片.视频等其它 ...

随机推荐

  1. String能变化吗?和StringBuffer的区别是什么

    [新手可忽略不影响继续学习]看 过上面例子的童鞋一定会觉得很奇怪,s = s + s1.charAt(i); 马克-to-win, s不是老在变化吗?其实s = "";时,虚拟机会 ...

  2. Unknown host mirrors.opencas.cn You may need to adjust the proxy settings in Gradle 报错及解决办法

    亲测Unknown host mirrors.opencas.cn You may need to adjust the proxy settings in Gradle 解决办法 - 程序员大本营 ...

  3. mysql绿色版安装以及遇到的问题

    下载mysql绿色版 放在如下文件夹  D:\javaSkill\mysql 修改my.ini文件内容: [mysql] default-character-set=utf8 [mysqld] bas ...

  4. Java 请求转发和重定向的区别以及JavaWeb三大作用域

    三大作用域以及转发和重定向 学习总结 1. 转发和重定向 转发 重定向 转发和重定向的区别: 什么时候用转发什么时候用重定向 三大作用域 作用域类型 作用域方法 如何选择作用域 总结 学习总结 1. ...

  5. MFC软件国际化的几个问题及其解决方案

    作者:马健 邮箱:stronghorse_mj@hotmail.com主页:https://www.cnblogs.com/stronghorse/ 以前我以为PDG相关软件只会在国内流行,所以发行简 ...

  6. CRLF 漏洞学习和工具使用

    原理 CRLF 指的是回车符(CR,ASCII 13,\r,%0d) 和换行符(LF,ASCII 10,\n,%0a),操作系统就是根据这个标识来进行换行的.但是如果对输入过滤不严,就会将恶意语句注入 ...

  7. Python入门-面向对象三大特性-封装

    一.封装 封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容. 所以,在使用面向对象的封装特性时,需要: 将内容封装到某处 从某处调用被封装的内容 第一步:将内容封装到某处 sel ...

  8. linux centos 8.2 安装docker

    1 使用yum -y install docker安装后启动docker提示Failed to start docker.service: Unit docker.service not found. ...

  9. FastDFS分布式的文件系统从小白入门到企业实践打怪之路系列笔记 【运维实践】

    描述: FastDFS 是阿里的余庆大佬用 C 语言编写的一款开源的分布式文件系统(个人项目),它对文件进行管理.功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,适合中小文件(4KB ...

  10. Dubbo-admin启动问题

    在Github上down了Dubbo-admin的最新文件,使用cmd命令打包完成后启动出现了问题,输出找不到2181端口的error. 百度只查询到是Dubbo-admin配置中的Zookeeper ...