CSS并不简单--一道微信面试题的实践

本文介绍CSS样式优先级计算规则,并演示如何利用原生JavaScript和html2canvas插件获取元素背景颜色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本系列会持续分享本人学习到的CSS知识点、技巧和效果展示。如有错误,希望您能指出。

前段时间有一位大牛分享的几道微信的面试题,其中一道是求一个元素的background-color的题目,鉴于对这道题目的学习,我写下了这篇文章。

优先级的计算规则

  • !important 这个关键字的优先级最高。要优化考虑使用样式规则的优先级来解决问题而不是 !important.

    下面要引入特殊值 0,0,0,0 每一位为0~255(基本上不会超过255的)

  • 内联样式. 记做: 1,0,0,0

  • 然后是ID选择器. 记做: 0,1,0,0
  • 类选择器、属性选择器和伪类选择器. 记做: 0,0,1,0
  • 元素选择器和伪元素选择器. 记做: 0,0,0,1
  • 通用选择器(星号)、组合符合(+,>,~,” “)和否定伪类(:not())不影响优先级.
  • 如果他们的优先级一样的话,则是后声明的样式覆盖前面声明的样式.

    举个简单的栗子:

  a:hover {
    color: red;
  }
  a:link {
    color: yellow;
  }

根据以上的计算规则我们可以得到 a:hover的优先级为 0,0,1,1,a:link的优先级也为 0,0,1,1。所以a:link的样式覆盖了a:hover。所以我们平常写这两个的不同样式时会把hover放在link的后面。

原生JS获取元素的样式

可能很多人用惯了jquery,突然让你用原生JS获取一个div的背景颜色,高高兴兴的搜了一个element.style.backgroundColor,然后一脸懵逼,为什么没有值?

  var d = document.querySelector('#d1');
  d.style.backgroundColor; //为什么它有时间没有值。

因为style不能读取样式表中的样式,是不是很尴尬!接下来让我们来感受一下JS的魅力:

  /**
   * 将属性名转化为驼峰命名格式
   */
  function camelize(str) {
    return str.replace(/-(\w)/g, function (matchStr, p1) {
      return p1.toUpperCase();
    })
  }

  function getStyle(element, name) {
    if (!element || !name) {
      return false;
    }

    //查看内敛样式是否存在 它的优先级最高 !important这里不考虑
    var value = element.style[name];
    if (value) {
      return value;
    }

    if (element.currentStyle) {
      //IE中
      value = element.currentStyle[name];
    } else {
      if (window.getComputedStyle) {
         //标准浏览器
         value = window.getComputedStyle(element, null).getPropertyValue(name);
      }
    }
    return value;
  }

是不是感觉其实原生的JS也是那么的优美,只是浏览器的兼容性埋没它的美丽。以上是个简单的获取元素某个样式属性的方法。其中还有很多问题,比如说!important。。。

在下面微信面试题求解的方法这篇文章的评论中,有人提到了用canvas的方式。然后我查阅了文档,看到了Drawing DOM Content To Canvas这篇文章,不过通过实践,发现通过svg将html元素转化图片,再填入到canvas中的方式,外部样式表并不能起作用。这就尴尬了,可能是我对那篇文章理解的还不够深刻(如果有人遇到同样的问题,能够指点一下),最终我选择了通过html2canvas插件实现我的需求。

  • 获取到目标元素的位置信息
  • 去除目标元素的后代元素, 以防止造成干扰判断。
  • 对整个页面进行截图,回调函数中恢复目标元素的后代节点。
  • 获取目标元素的像素集合。
  • 因为只能获取到一个个的像素点,我这里只想到了去掉border区域的其他的某点颜色作为背景颜色。
  • 这里只能判断纯色背景(好像有点蠢),有更好的判断方法,请留言指点。

    直接上代码:

  const canvas = document.createElement('canvas'),
        context = canvas.getContext('2d'),
        div = document.querySelector('.demo1');


  const rect = div.getBoundingClientRect(), //获取元素的位置信息
        x = rect.left,
        y = rect.top,
        w = rect.width,
        h = rect.height;

  canvas.width = document.body.clientWidth;
  canvas.height = document.body.clientHeight;

  function getColor() {
    //去掉目标元素的后代元素
    let childnodes = removeChilds(div);
    //对页面进行截屏
    html2canvas(document.body, {canvas: canvas}).then((canvas) => {
      //获取目标元素的像素集合
      const imageData = context.getImageData(x,y,w,h);

      //恢复目标元素的后代元素
      addChilds(div, childnodes);
      childnodes = null;

      /**
       * 去掉border的影响
       */
      const border = parseInt(getStyle(div,"border-width"));
      const index =  (border * w + border) * 4;
      const r = imageData.data[index],
            g = imageData.data[index + 1],
            b = imageData.data[index + 2],
            a = imageData.data[index + 3];
      console.log("rgba(" + r + "," + g + "," + b + "," + a + ")");
    });
  }


  //剥离后代元素
  function removeChilds(element) {
    let eleArray = Array.from(element.childNodes);
    eleArray.forEach((item) => {
      element.removeChild(item);
    })
    return eleArray;
  }

  //加上后代元素
  function addChilds(element, nodes) {
    nodes.forEach((item) => {
      element.appendChild(item);
    })
  }

到这里,这个题目也告一段落了。哈哈,感觉您用心的看完,给你点个赞。如果文章有误,望君评论指点。

参考文章:
* MDN
* 王美建的文章
* 微信面试题求解的方法
* Drawing DOM Content To Canvas

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值