资讯专栏INFORMATION COLUMN

CSS魔法堂:一起玩透伪元素和Content属性

DevTalking / 1862人阅读

摘要:前言继上篇魔法堂稍稍深入伪类选择器记录完伪类后,我自然而然要向伪元素伸出魔掌的啦。和的注意事项默认必须设置属性,否则一切都是无用功默认,就是和的内容无法被用户选中的伪元素和伪类结合使用形如。

前言

 继上篇《CSS魔法堂:稍稍深入伪类选择器》记录完伪类后,我自然而然要向伪元素伸出“魔掌”的啦^_^。本文讲讲述伪元素以及功能强大的Contet属性,让我们可以通过伪元素更好地实现更多的可能!

初识伪元素

 说起伪元素我第一想到的莫过于::before::after这两个了,它俩其实就是在其附属的选择器命中的元素上插入第一个子节点和追加最后一个子节点。那这时我不禁地想问:“直接添加两个class为.before和.after不是一样的吗?”
 其实使用伪元素::before::after以下两个好处:

HTML的代码量减少,对SEO有帮助;

提高JavaScript查询元素的效率。

 那为什么会这两好处呢?原因就是伪元素并不存在于DOM中,而是位于CSSOM,HTML代码和DOM Tree中均没有它的身影,量少了自然效率有所提升。但这也引入一个问题——我们没办法通过JavaScript完全操控伪元素(我将在下面一节为大家讲述)

一大波伪元素来了

除了::before::after外,别漏了以下的哦!

:first-line:只能用于块级元素。用于设置附属元素的第一个行内容的样式。可用的CSS属性为font,color,background,word-spacing,letter-spacing,text-decoration,vertical-align,text-transform,line-height,clear

:first-letter:只能用于块级元素。用于设置附属元素的第一个字母的样式。可用的CSS属性为font,color,background,marin,padding,border,text-decoration,vertical-align,text-transform,line-height,float,clear

::selection:匹配选中部分的内容。可用的CSS属性为background,color

有没有发现有的伪元素前缀是:有的却是::呢?::是CSS3的写法,其实除了::selection外,其他伪元素既两种前缀都是可以的,为兼容性可选择使用:,为容易区分伪元素和伪类则使用::,但我还是建议使用::来提高可读性,兼容性就让postcss等工具帮我们处理就好了。

::before::after的注意事项

默认display: inline

必须设置content属性,否则一切都是无用功;

默认user-select: none,就是::before::after的内容无法被用户选中的;

伪元素和伪类结合使用形如:.target:hover::after

JavaScript操作伪元素

 上文提到由于伪元素仅位于CSSOM中,因此我们仅能通过操作CSSOM API——window.getComputedStyle来读取伪元素的样式信息,注意:我们能做的就是读取,无法设置的哦!

</>复制代码

  1. {- window.getComputedStyle的类型 -}
  2. data PseudoElement = ":before" | "::before" | ":after" | "::after" | ":first-line" | "::first-line" | ":first-letter" | "::first-letter" | "::selection" | ":backdrop" | "::backdrop" | Null
  3. window.getComputedStyle :: HTMLElement -> PesudoElement -> CSSStyleDeclaration
  4. {- CSSStyleDeclaration实例的方法 -}
  5. data CSSPropertyName = "float" | "backround-color" | ......
  6. data DOMPropertyName = "cssFloat" | "styleFloat" | "backgroundColor" | ......
  7. -- IE9+的方法
  8. CSSStyleDeclaration#getPropertyValue :: CSSPropertyName -> *
  9. -- IE6~8的方法
  10. CSSStyleDeclaration#getAttribute :: CSSPropertyName -> *
  11. -- 键值对方式获取
  12. CSSStyleDeclaration#[DOMPropertyName] -> *

示例:

</>复制代码

  1. .target[title="hello world"]::after{
  2. display: inline-block;
  3. content: attr(title);
  4. background: red;
  5. text-decoration: underline;
  6. }
  7. const elTarget = document.querySelector(".target")
  8. const computedStyle = window.getComputedStyle(elTarget, "::after")
  9. const content = computedStyle.getPropertyValue("content")
  10. const bg = computedStyle.getAttribute("backgroundColor")
  11. const txtDecoration = computedStyle["text-decoration"]
  12. console.log(content) // "hello world"
  13. console.log(bg) // red
  14. console.log(txtDecoration) // underline
玩透Content属性

 到这里我们已经可以利用::before::after实现tooltip等效果了,但其实更为强大的且更需花时间研究的才刚要开始呢!那就是Content属性,不仅仅可以简单直接地设置一个字符串作为伪元素的内容,它还具备一定限度的编程能力,就如上面attr(title)那样,以其附属元素的title特性作为content值。下面请允许我为大家介绍吧!

</>复制代码

  1. div::after{
  2. content: "普通字符串";
  3. content: attr(父元素的html属性名称);
  4. content: url(图片、音频、视频等资源的url);
  5. /* 使用unicode字符集,采用4位16进制编码
  6. * 但不同的浏览器显示存在差异,而且移动端识别度更差
  7. */
  8. content: "21e0";
  9. /* content的多个值可以任意组合,各部分通过空格分隔 */
  10. content: """ attr(title) """;
  11. /* 自增计数器,用于插入数字/字母/罗马数字编号
  12. * counter-reset: [ ?]+,必选,用于标识自增计数器的作用范围,为自定义名称,为起始编号默认为0
  13. * counter-increment: [ ?]+,用于标识计数器与实际关联的范围,为counter-reset中的自定义名称,为步长默认为1
  14. * : disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha
  15. */
  16. content: counter(, );
  17. /* 以父附属元素的qutoes值作为content的值
  18. */
  19. content: open-quote | close-quote | no-open-quote | no-close-quote;
  20. }

换行符:HTML实体为 ,CSS为A,JS为uA

 可以看到Content接受6种类型,和一种组合方式。其中最后两种比较复杂,我们后面逐一说明。

自定义计数器

 HTML为我们提供ulolli来实现列表,但如果我们希望实现更为可性化的列表,那么该如何处理呢?content属性的counter类型值就能帮到我们。

</>复制代码

  1. .dl
  2. .dt{chapter1}
  3. .dd{text11}
  4. .dd{text12}
  5. .dt{chapter2}
  6. .dd{text21}
  7. /* CSS部分 */
  8. .dl {
  9. counter-reset: dt 0; /* 表示解析到.dl时,重置dt计数器为0 */
  10. & .dt {
  11. counter-reset: dd 0; /* 表示解析到.dt时,重置dd计数器为0 */
  12. &::before{
  13. counter-increment: dt 1; /* 表示解析到.dt时,dt计数器自增1 */
  14. content: counter(dt, lower-roman) " ";
  15. }
  16. }
  17. & .dd::before {
  18. counter-increment: dd 1; /* 表示解析到.dd时,dd计数器自增1 */
  19. content: counter(dd) " ";
  20. }
  21. }

通过counter-reset来定义和重置计数器,通过counter-increment来增加计数器的值,然后通过counter来决定使用哪个计数器,并指定使用哪种样式。
 如果用JavaScript来表示应该是这样的

</>复制代码

  1. const globalCounters = {"__temp":{}}
  2. function resetCounter(name, value){
  3. globalCounters[name] = value
  4. }
  5. function incrementCounter(name, step){
  6. const oVal = globalCounters[name]
  7. if (oVal){
  8. globalCounters[name] = oVal + step
  9. }
  10. else{
  11. globalCounters.__temp[name] = step
  12. }
  13. }
  14. function counter(name, style){
  15. return globalCounters[name] || globalCounters.__temp[name]
  16. }
  17. function applyCSS(mount){
  18. const clz = mount.className
  19. if (clz == "dl"){
  20. resetCounter("dt", 0)
  21. const children = mount.children
  22. for (let i = 0; i < children.length; ++i){
  23. applyCSS(children[i])
  24. }
  25. }
  26. else if (clz == "dt"){
  27. resetCounter("dd", 0)
  28. incrementCounter("dt", 1)
  29. const elAsBefore = document.createElement("span")
  30. elAsBefore.textContent = counter("dt", "lower-roman") + " "
  31. mount.insertBefore(mount.firstChild)
  32. }
  33. else if (clz == "dd"){
  34. incrementCounter("dd", 1)
  35. const elAsBefore = document.createElement("span")
  36. elAsBefore.textContent = counter("dd", "lower-roman") + " "
  37. mount.insertBefore(mount.firstChild)
  38. }
  39. }
嵌套计数器

 对于多层嵌套计数器我们可以使用counters(, , ?)

</>复制代码

  1. .ol
  2. .li
  3. .ol
  4. .li{a}
  5. .li{b}
  6. .li
  7. .ol
  8. .li{c}

</>复制代码

  1. .ol {
  2. counter-reset: ol;
  3. & .li::before {
  4. counter-increment: ol;
  5. content: counters(ol, ".");
  6. }
  7. }
Content的限制

IE8+才支持Content属性;

除了Opera9.5+中所有元素均支持外,其他浏览器仅能用于:before,:after内使用;

无法通过JS获取Counter和Counters的运算结果。得到的就只能是"counter(mycouonter) " ""

自定义引号

 引号这个平时很少在意的符号,其实在不同的文化中使用的引号将不尽相同,如简体中文地区使用的"",而日本则使用「」。那我们根据需求自定义引号呢?答案是肯定的。
 通过open-quote,close-quote,no-open-quoteno-close-quote即可实现,下面我们通过例子来理解。
会根据父元素的lang属性自动创建::before::after来实现插入quotation marks。

</>复制代码

  1. p[lang=en]>q{英语}
  2. p[lang=no]>q{挪威语}
  3. p[lang=zh]>q{汉语}
  4. p[lang=en]>q.no-quote{英语2}
  5. div[lang=no]>.quote{挪威语2}

CSS片段:

</>复制代码

  1. p[lang=en] > q{
  2. quotes: ""; /* 定义引号 */
  3. }
  4. p[lang=en] > q.no-quote::before{
  5. content: no-open-quote;
  6. /*或者 content: none;*/
  7. }
  8. div[lang=no] > .quote {
  9. quotes: "<<-" "->>";
  10. }
  11. div[lang=no] > .quote::before {
  12. content: open-quote;
  13. }
  14. div[lang=no] > .quote::after {
  15. content: close-quote;
  16. }

示例 分割线

</>复制代码

  1. p.sep{or}

</>复制代码

  1. .sep {
  2. position: relative;
  3. text-align: center;
  4. &::before,
  5. &::after {
  6. content: "";
  7. box-sizing: border-box;
  8. height: 1px;
  9. width: 50%;
  10. border-left: 3em solid transparent;
  11. border-right: 3em solid transparent;
  12. position: absolute;
  13. top: 50%;
  14. }
  15. &::before {
  16. left: 0;
  17. }
  18. &::after {
  19. right: 0;
  20. }
  21. }
只读效果(通过遮罩原来的元素实现)

</>复制代码

  1. .input-group {
  2. position: relative;
  3. &.readonly::before {
  4. content: "";
  5. position: absolute;
  6. width: 100%;
  7. height: 100%;
  8. top: 0;
  9. left: 0;
  10. }
  11. }
计数器

</>复制代码

  1. .selections>input[type=checkbox]{option1}+input[type=checkbox]{option2}
  2. .selection-count

</>复制代码

  1. .selections{
  2. counter-reset: selection-count;
  3. & input:checked {
  4. counter-increment: selection-count;
  5. }
  6. }
  7. .selection-count::before {
  8. content: counter(selection-count);
  9. }
最后

 尊重原创,转载请注明来自:https://www.cnblogs.com/fsjoh... 肥仔John^_^

参考

http://www.wozhuye.com/compat...
https://dev.opera.com/article...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/116949.html

相关文章

  • CSS魔法:display:none与visibility:hidden的恩怨情仇

    摘要:不耽误表单提交数据虽然我们无法看到的元素,但当表单提交时依然会将隐藏的元素的值提交上去。让元素在见面上不可视,但保留元素原来占有的位置。不过由于各浏览器实现效果均有出入,因此一般不会使用这个值。继承父元素的值。 前言  还记得面试时被问起请说说display:none和visibility:hidden的区别吗?是不是回答完display:none不占用原来的位置,而visibilit...

    selfimpr 评论0 收藏0
  • CSS魔法:重拾Border之——图片作边框

    摘要:一铺搞定一铺清袋粤语的一铺搞定其实就是一次完成全部工作的意思,上面关于的属性,要是每次都逐个设置那要敲多少次键盘啊。。。语法粤语的一铺清袋其实就是把之前的成果一次性归零。 前言  当CSS3推出border-radius属性时我们是那么欣喜若狂啊,一想到终于不用再添加额外元素来模拟圆角了,但发现border-radius还分水平半径和垂直半径,然后又发现border-top-left/...

    linkFly 评论0 收藏0
  • CSS魔法:小结一下Box Model与Positioning Scheme

    摘要:魔法堂重新认识和魔法堂你一定误解过的魔法堂就这个样魔法堂说说那个被埋没的志向深入细节后会发现中定位模式之间,和之间存在千丝万缕的关系,必须以俯瞰的角度捋一下。当采用时,属性的实际值会被重置为。由于和则需要通过来引入来提供盒子定位微调的功能。 前言  对于Box Model和Positioning Scheme中3种定位模式的细节,已经通过以下几篇文章记录了我对其的理解和思考。 《CSS...

    szysky 评论0 收藏0
  • CSS魔法:说说Float那个被埋没的志向

    摘要:时其宽度始终保持占满宽度的态度。清除浮动就是为浮动影响的范围划边界。那么可归结为的父容器包裹所有子元素。注意属性值不能为空白,否则无法清除浮动。 前言  定位系统中第一难理解就是Normal flow,而第二就非Float莫属了,而Float难理解的原因有俩,1. 一开头我们就用错了;2. 它跟Normal flow靠得太近了。本文尝试理清Float的特性和行为特征,若有纰漏望各位指正...

    legendmohe 评论0 收藏0
  • CSS魔法:稍稍深入伪类选择器

    摘要:前言过去零零星星地了解和使用和等伪类伪元素选择器,最近看书时发现这方面有所欠缺,于是决定稍微深入学习一下,以下为伪类部分的整理。伪类伪类选择器实质上是让设计师可以根据元素特定的状态,设置不同的视觉效果。也就是符合以下选择器的元素均支持状态。 前言  过去零零星星地了解和使用:link、::after和content等伪类、伪元素选择器,最近看书时发现这方面有所欠缺,于是决定稍微深入学习...

    tanglijun 评论0 收藏0

发表评论

0条评论

DevTalking

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<