chokcoco / iCSS

不止于 CSS
19.63k stars 2.01k forks source link

谈谈一些有趣的CSS题目(2)-- 条纹边框的多种实现方式 #1

Open chokcoco opened 8 years ago

chokcoco commented 8 years ago

开本 issues ,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节。

解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉到生僻的 CSS 属性,赶紧去补习一下吧。

不断更新,不断更新,不断更新,重要的事情说三遍。

2、类似下面这个图形,只使用一个标签,可以有多少种实现方式:

image

假设我们的单标签为 div:

<div></div>

定义如下通用 CSS:

div{
    position:relative;
    width: 180px;
    height: 180px;
}

这一题主要考查的是盒子模型 Box Model 与 背景 background 的关系,以及使用 background-clip 改变背景的填充方式。

backgroundBox Model 中,他是布满整个元素的盒子区域的,并不是从 padding 内部开始(也就是说从 border 就开始啦),只不过实线边框(solid)部分遮住了部分 background ,所以我们使用虚线边框(dashed)就可以看到背景色是从 border 内部开始的。

我们给 div 添加如下样式:

div{
    background:#9c27b0;
    border:20px dashed #2196f3;
}

结果如下:

image

但有一点需要注意,background-color 是从元素的边框左上角起到右下角止,而 background-image 却不一样,他是从 padding 边缘的左上角起而到 border 的右下角边缘止。

background image 的绘制中有两个因素决定了绘图区域:

  1. background positioning areabackground-origin 属性决定了这个相对定位位置,默认为 padding-box。所以默认的背景图片绘制是从 padding box 的左上顶点开始的。
  2. background painting areabackground-clip 属性决定了绘制区间,默认为 border-box。所以在 background-repeat: repeat 的情况下:

The image is repeated in this direction as often as needed to cover the background painting area.

嗯,什么意思呢,你可以戳进这个 demo 看看,正常情况下的背景图填充如下:

image

当然,这个填充规则是可以通过 background-clip 改变的。

background-clip 设置元素的背景(背景图片或颜色)是否延伸到边框下面。

语法:

background-clip: border-box;  // 背景延伸到边框外沿(但是在边框之下)
background-clip: padding-box; // 边框下面没有背景,即背景延伸到内边距外沿。
background-clip: content-box; // 背景裁剪到内容区 (content-box) 外沿。

继续说回本题,接下来,只需要将中间部分填充为白色即可,这个用伪元素可以轻松完成,所以,其中一个方法如下:

div{
    background:#9c27b0;
    border:20px dashed #2196f3;
}
div::after{
    content:"";
    position:absolute;
    top:0;
    left:0;
    bottom:0;
    right:0;
    background:#fff;
}

法二:

上面的方法,我们使用了 div 的背景色默认情况下从 border 开始填充,及伪元素设置白色背景色填充 div 的中间的 padding-box 区域完成图形。

也可以反过来,使用伪元素背景色从 border-box 开始填充,使用 div 的背景色填充中间 padding-box区域。

div{
    background:#fff;
    background-clip:padding-box;
    border:20px dashed #cccc99;
}
div::before{
    content:"";
    position:absolute;
    top:-20px;
    left:-20px;
    bottom:-20px;
    right:-20px;
    background:#996699;
    z-index:-1;
}

具体的 Demo 戳这里 。

上面 法二 除了用到了 background-clip 改变背景的填充区域,还用到了 z-index 触发元素生成了堆叠上下文(stacking context),改变了元素的层叠顺序(stacking levle),让伪元素背景色叠到了 div 背景色 之下,这两个概念下题会提及。

法....

本题主要是想讨论一下 CSS 的盒子模型 Box Model 与 背景 background 的关系,其实本题就是在于一个 dashed 边框,内部使用颜色填充即可,与上面第一题异曲同工,使用阴影、渐变都可以完成,感兴趣可以自己尝试一下其他解法。

idiotWu commented 8 years ago

background-image 默认也是从 border-box 延展开的:

2016-09-19 19 40 22

wangpengfei15975 commented 8 years ago

+1

chokcoco commented 8 years ago

@idiotWu 刚刚没看清楚就瞎回复了,见谅。 看你图中的确实是从 border 开始的,有demo吗,我这边的demo都是从 paading-box 开始的。 CssBackground

idiotWu commented 8 years ago

@chokcoco 查了相关的标准,发现原因在于你设定了 background-repeat: no-repeat

background image 的绘制中有两个因素决定了绘图区域:

  1. background positioning areabackground-origin 属性决定了这个相对定位位置,默认为 padding-box。所以默认的背景图片绘制是从 padding box 的左上顶点开始的。
  2. background painting areabackground-clip 属性决定了绘制区间,默认为 border-box。所以在 background-repeat: repeat (default)的情况下:

The image is repeated in this direction as often as needed to cover the background painting area.

chokcoco commented 8 years ago

@idiotWu 感谢提出,我正好也在查看标准是怎么定义的,我补充到题中去。

wangpengfei15975 commented 8 years ago

嗯 吹毛求疵一下。 第四题的法2为什么不直接用rotateX = =

chokcoco commented 8 years ago

@wangpengfei15975 厉害了我的哥,两个写法确实是一样的,rotateX 应该是更简洁的。

zhanhongtao commented 8 years ago

第五个, 已经用了 flex box, 可以直接在侧轴方向上居中. DEMO

Serena211 commented 8 years ago

sorry, 刚刚发错地方了。第二个dashed border box 的outline解法

.style_outline { &::before{ content:""; position:absolute; top:0; left:0; bottom:0; right:0; outline:20px solid #ffc107; background:#fff; z-index:-1; } 感觉这样更合理一点。

bytemofan commented 7 years ago

非常有意思

jiangxiaolin1995 commented 7 years ago

啊哈,脑洞好大啊

OnionStu commented 7 years ago

第5题,如果加上点击加载更多呢…要如何实现?

github302 commented 7 years ago

第1题,当用border-left设置样式的时候,div的整个宽度就会加长,如果想要div整体宽度不变的话,就需要加上box-sizing:border-box; 使用外 box-shadow的时候div宽度也会加长,内 box-shadow就不会,所以如果需求还要保证div整体宽度不变的话,得注意下这些点。

`.demo1 { position:relative; width:200px; height:60px; background:#ddd; }

.demo2 { position:relative; width:200px; height:60px; background:#ddd; }

.demo2:after { position:absolute; left:0; top:0; content:''; width:5px; height:60px; background: deeppink; }

.demo3 { position:relative; width:200px; height:60px; background:#ddd; box-shadow: inset 5px 0 0 deeppink; }

.demo4 { position:relative; width:200px; height:60px; background:#ddd; border-left:solid 5px deeppink; box-sizing:border-box; } .demo5 { position:relative; width:200px; height:60px; background:#ddd; box-shadow:-5px 0 0 deeppink; } .demo6 { position:relative; width:200px; height:60px; background:#ddd; border-left:solid 5px deeppink; }







` 可以对比看下容器宽度

olovey commented 7 years ago

好厉害啊,刚入前端,真的学习到很多。谢谢

chokcoco commented 7 years ago

@olovey 建议去我的博客读这些文章,可以看到Demo,效果更好,github没办法嵌入iframe。

desperadoray commented 7 years ago
  1. 法3 [code] box-shaodw -> shadow
wmh1106 commented 7 years ago

第四题:如果是倒影,还可以用缩放来做的scale demo

jokum commented 7 years ago

第一个:不知道用背景图片(repeat-y)算不算

llqkl commented 6 years ago

专门注册了来问一下,为什么第二题的法一,我得到的结果是这样的呢,边框从左上角开始,但是是连着的,不是左上角一个小方块那种 qq 20180515104238

Jemair commented 6 years ago

关于移动端多行省略 我这里有个更好的实现 https://codepen.io/isjemair/pen/oMRZvm 切换最外层的folded类名就可以实现查看更多和收起状态

法一的实现不能实现点击查看更多 法二的实现很容易造成文字被截一半

原本的方法是在网上找到一个老外的 我在做的时候是把其中的参数抽出来作为变量

huan-joy commented 6 years ago

关于前两个问题,其实还可以直接用img标签嘛(要是说不能包含外部图片,可以把图片转成base64编码嘛),同理还可以使用svg标签嘛。

zsjun commented 6 years ago

image

专门注册了来问一下,为什么第二题的法一,我得到的结果是这样的呢,边框从左上角开始,但是是连着的,不是左上角一个小方块那种 qq 20180515104238 我的也是,感觉是lz写法有问题

chokcoco commented 6 years ago

@zsjun 我尝试了下现版本的chrome下确实是上图你发的效果。 因为写这个这篇文章的时间距离现在有一段时间了,我再去确认考究下,再给你个答复~

zsjun commented 6 years ago

@zsjun 我尝试了下现版本的chrome下确实是上图你发的效果。 因为写这个这篇文章的时间距离现在有一段时间了,我再去确认考究下,再给你个答复~

好的,多谢,我用的是goole浏览器的69.0.3497.100版本,最新的版本

mask2012 commented 6 years ago

关于移动端多行省略 我这里有个更好的实现 https://codepen.io/isjemair/pen/oMRZvm 切换最外层的folded类名就可以实现查看更多和收起状态

法一的实现不能实现点击查看更多 法二的实现很容易造成文字被截一半

原本的方法是在网上找到一个老外的 我在做的时候是把其中的参数抽出来作为变量

@Jemair 你的demo的问题是展开是用颜色盖在上边的,所以底部背景变化,或不是纯色会露出马脚 image

spadek-w commented 6 years ago

第3个父元素 display: flex;flex-direction: row-reverse; 子元素margin-left:负值 好像也行

wd2010 commented 5 years ago

大神你好,这些思考非常值得学习。关于第2道思考题我在backgroun-image和background-color上有点疑惑想请教下。下图是我通过伪元素实现的,但我想通过background-image的多背景实现,内部的background-image的终止点总是在border右下角,我想把它终止点在padding右下角,请问可以怎么实现呢? 1111111111

以下是我想实现的代码,但不起作用

div{
      margin:20px;
      width: 400px;
      height:400px;
      border: 10px dashed green;
      padding: 20px;
      background-repeat: no-repeat, no-repeat;
      background-image:
          url(./img/1.jpg),
          linear-gradient(to right, red,red);
      background-clip: padding-box, border-box;
    }
weijiyang commented 5 years ago

"嗯,什么意思呢,你可以戳进这个 demo 看看,正常情况下的背景图填充如下" 感觉这个demo里面的和后面加菲猫配图讲解的不太相符 代码中background-clip 默认都是border-box 在border之下 但是加菲猫图片说背景图是padding左上角到border 右下角 还是我的理解有问题?

gentlecoder commented 5 years ago
background-image: linear-gradient(to left,white,white);
background-repeat: no-repeat;

直接在div加上这两个样式好像也行