zoukankan      html  css  js  c++  java
  • CSS魔法堂:重拾Border之——不仅仅是圆角

    前言

     当CSS3推出border-radius属性时我们是那么欣喜若狂啊,一想到终于不用再添加额外元素来模拟圆角了,但发现border-radius还分水平半径和垂直半径,然后又发现border-top-left/right-radius的水平半径之和大于元素宽度时,实际值会按比例分配元素宽度时,不禁会问"我真的懂border吗?"。本系列将稍微深入探讨一下那个貌似没什么好玩的border!
    《CSS魔法堂:重拾Border之——解构Border》
    《CSS魔法堂:重拾Border之——图片作边框》
    《CSS魔法堂:重拾Border之——不仅仅是圆角》
    《CSS魔法堂:重拾Border之——更广阔的遐想》

    圆角进化论

     当设计稿上出现圆角按钮/标签页时,我们会如何应对呢?CSS3到来之前最广为人知的应该就是"滑动门"(sliding door)实现方式了。

    滑动门实现法

    <style type="text/css">
    ul{padding:0;margin:0;}
    li{padding:0;margin:0;list-style:none;}
    a{margin:0;text-decoration:none;}
    
    /*clearfix*/
    .nav{
      *zoom: 1;
    }
    .nav::after{
      content: ".";
      display: block;
      clear: both;
      line-height: 0;
      visibility: hidden;
    }
    /*滑动门实现Tab*/
    .nav .nav-item{
      float: left;
      margin-right: 5px;
    }
    .nav .nav-item a{
      display: inline-block;
      background: url("./background.jpg") no-repeat;
      color:#333;
      font-size: 12px;
      line-height: 2;
    }
    .nav .nav-item a span{
      display: inline-block;
      background: url("./background.jpg") no-repeat right top;
      padding: 0 10px 0 5px;
      margin-left: 5px;
    }
    
    .nav .nav-item a:hover{
      background: url("./background.jpg") no-repeat left -30px;
    }
    .nav .nav-item a:hover span{
      background: url("./background.jpg") no-repeat right -30px;
    }
    </style>
    <ul class="nav">
      <li class="nav-item"><a href="javascript:void 0"><span>首页</span></a></li>
      <li class="nav-item"><a href="javascript:void 0"><span>PDCA检验单查询</span></a></li>
      <li class="nav-item"><a href="javascript:void 0"><span>成品通用标准审核</span></a></li>
    </ul>
    

    border-radius实现法

    border-top-left-radius: [<length>|<percentage>]{1,2}
    border-top-right-radius: [<length>|<percentage>]{1,2}
    border-bottom-left-radius: [<length>|<percentage>]{1,2}
    border-bottom-right-radius: [<length>|<percentage>]{1,2}
    设置左上/右上/左下/右下角水平和垂直椭圆半径
    <length>:以带单位的绝对值作为半径;
    <percentage>:以对应border box的尺寸(不是border-width)为参考系,设置半径;
    注意:结果值为0(默认值)时,为直角边框
    border-radius: [<length>|<percentage>]{1,4} [/[<length>|<percentage>]{1,4}]?:一次过设置4个角的椭圆半径

     从上图我们可以看到4个角分别对应4个独立的椭圆形,而圆角正是4分之1个椭圆。
    撸代码!

    <style type="text/css">
    /*clearfix*/
    .nav3{
      *zoom: 1;
    }
    .nav3::after{
      content: ".";
      display: block;
      clear: both;
      line-height: 0;
      visibility: hidden;
    }
    /*border-radius实现Tab*/
    .nav3 .nav-item3{
      float: left;
      margin-right: 5px;
    }
    .nav3 .nav-item3 a{
      font-size: 12px;
      line-height: 2;
    
      display: inline-block;
      background: #0ac;
      padding: 0 10px;
      border: 1px solid #eee;
      border-radius: 8px 8px 0 0;
    }
    .nav3 .nav-item3 a:hover{
      background: #eef;
    }
    </style>
    <ul class="nav3">
      <li class="nav-item3"><a href="javascript:void 0">首页</a></li>
      <li class="nav-item3"><a href="javascript:void 0">PDCA检验单查询</a></li>
      <li class="nav-item3"><a href="javascript:void 0">成品通用标准审核</a></li>
    </ul>
    

    圆角的何止是border box啊


     上图的content box变成椭圆形了,而且content box中的文字好像飘到content box外面。但确实是content box变为椭圆形还是说仅仅是背景色是如此而已呢?让我们添加overflow:hidden看看效果吧

     看来border-radius确实影响到content box了。其实border-radius将会影响到box model中的所有box。当我们通过border-radius设置border box的椭圆半径后,CSS渲染引擎会根据公式自动计算出margin/padding/content box的椭圆半径,然后为它们渲染出圆角。
    注意

    1. margin/border/padding/content box中相同方向的角的椭圆的圆心重叠;
    2. 当椭圆半径为0时,渲染为直角。

    margin box圆角了

    公式:margin-radius = border-radius + margin-width
    border-radius > margin-width时,margin-width=1 + (margin-width/border-radius-1)^3以确保margin-radius趋向于直角。

    padding box圆角了

    公式:padding-radius = border-radius + border-width
    当padding-radius为0时,渲染为直角

    <style type="text/css">
    .s1{
    background: #FEE;
     0;
    padding: 50px;
    border: 10px solid red;
    border-radius: 10px;
    
    float:left;
    margin-right: 20px;
    }
    .s2{
    background: #FEE;
     0;
    padding: 50px;
    border: 10px solid red;
    border-radius: 20px;
    
    float:left;
    }
    </style>
    <div class="s1"></div>
    <div class="s2"></div>
    

    content box/area圆角了

    公式:content-radius = border-radius + border-width - padding-width
    当content-radius为0时,渲染为直角

    <style type="text/css">
    .s1{
    background: #FEE;
     100px;
    height: 100px;
    border: 10px solid red;
    border-radius: 10px;
    
    float:left;
    margin-right: 20px;
    }
    .s2{
    background: #FEE;
     100px;
    height: 100px;
    border: 10px solid red;
    border-radius: 20px;
    
    float:left;
    }
    </style>
    <div class="s1"></div>
    <div class="s2"></div>
    

    注意
    由于margin区域无法触发点击等事件,而圆角border box所占面积必定小于直角border box,因此为保持可点击区域面积,圆角border box应设置更大的高宽值。

    话说"大值特性"和"等比特性"

     @张鑫旭老师在《秋月何时了,CSS3 border-radius知多少?》提到"大值特性"和"等比特性"两个特性。

    <style type="text/css">
    .s1{
    box-sizing: border-box;
    background: #FEE;
     100px;
    height: 200px;
    border: 10px solid red;
    border-top-left-radius: 100px 200px;
    
    float: left;
    margin-right: 20px;
    }
    .s2{
    box-sizing: border-box;
    background: #FEE;
     100px;
    height: 200px;
    border: 10px solid red;
    border-top-left-radius: 200px;
    
    float: left;
    }
    </style>
    <div class="s1"></div>
    <div class="s2"></div>
    

    你看div.s2明明把左上角的水平和垂直半径设置为200px,但实际效果却是两者结果值均为100px,难道这就是"大值特性"?

    <style type="text/css">
    .s1{
    box-sizing: border-box;
    background: #FEE;
     200px;
    height: 100px;
    border: 10px solid red;
    border-top-left-radius: 300px 100px;
    border-top-right-radius: 900px 100px;
    }
    </style>
    <div class="s1"></div>
    

    仅仅看div.s1水平方向的椭圆半径,left和right相加300+900=1200远远大于border box的宽度200px,也就是说两个椭圆将发生重叠。对于这种情况CSS渲染引擎到底是如何处理的呢?

    1. 首先明确的是left+right必须小于等于border-box的宽度,也就是说两个椭圆不能发生重叠。
    2. 然后根据"等比例特性"得到left/(left+right)=300/(300+900)=1/4right/(left+right)=900/(300+900)=3/4,得到left结果值为200/4=50,right结果值为3*200/4=150

     通过"等比例特性"我们很好地解释了上图中水平方向的效果,但大家有没有发现垂直方向的半径有点奇怪呢?我们明明设置半径为100px,而且border box的高度恰好也是100px,按理应该是足够的,为何垂直半径的结果值不是100px呢?
     其实W3C Spec中已经说得很清楚了!

    Let f = min(Li/Si), where i ∈ {top, right, bottom, left}, Si is the sum of the two corresponding radii of the corners on side i, and Ltop = Lbottom = the width of the box, and Lleft = Lright = the height of the box. If f < 1, then all corner radii are reduced by multiplying them by f.

    其实"最大值特性"和"等比例特性"只是上述规则的表象而已,最根本的公式为f=min(Li/Si)
    以第二个示例来计算一下吧
    计算f的值

    1. top-left和top-right的水平半径之和为1200px,而border box宽度为200px,那么f1=200/1200=1/6;
    2. top-left和bottom-left的垂直半径之和为400px,而border box高度为400px,那么f2=400/400=1;
    3. bottom-left和bottom-right的水平半径为0,忽略;
    4. top-right和bottom-right的垂直半径之和为400px,而border box高度为400px,那么f3=400/400=1;
    5. f=min(f1,f2,f3),结果为f=f1

    缩放各半径

    1. top-left和top-right的水平半径分别乘以f,得到结果值300/6=50900/6=150;
    2. top-left和top-right的垂直半径分别乘以f,得到结果值400/6=66.66

    被忽视的猪脚——相交线

     当设置border-leftborder-top后,我们很容易预测到左边框和上边框的样式,但它俩相交部分的样式呢?这里就涉及到相交线的问题了!

    通过直角边框找相交线

     圆角边框是基于直角边框的,这一点也体现在相邻边框的相交线上。

    <style type="text/css">
      .box{
         100px;
        height: 200px;
        border: 50px solid;
        border-left-color: red;
        border-top-color: blue;
        border-right-color: green;
        border-bottom-color: yellow;
      }
    </style>
    <div class="box"></div>
    


     我们可以看到两边相交所形成的矩形的对角线,将作为边的相交点。通过相交点判断边框样式应应用到哪一条边上。
    透视图如下

    延长相交线

     由于圆角边框不像直角边框那样有棱有角,因此更难以分辨边框样式所对应的边框。但只要我们沿直角边框的相交线向图形内延伸,一切则清晰明了了。

    <style type="text/css">
      .rounded-box{
         100px;
        height: 200px;
        border: 50px solid;
        border-left-color: red;
        border-top-color: blue;
        border-right-color: green;
        border-bottom-color: yellow;
        border-radius: 100px;
      }
    </style>
    <div class="rounded-box"></div>
    


    透视图如下

    兼容性


     虽然各大浏览器均支持border-radius属性,但其实现效果却不尽相同,我们拿极端情况来作试验,最能看出效果。结论是让我们大跌眼镜的:IE效果最为理想!!

    <style type="text/css">
    .s1{
      box-sizing: border-box;
       200px;
      height: 200px;
      border: 50px solid;
      border-color: red blue green yellow;
    
      border-top-left-radius: 50% 100%;
      border-top-right-radius: 50% 100%;
    }
    </style>
    <div class="s1"></div>
    

    chrome34中

    FF中

    IE9

    总结

     尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/5458573.htm_肥仔John

    感谢

    CSS Backgrounds and Borders Module Level 3 4. Borders
    秋月何时了,CSS3 border-radius知多少?
    CSS滑动门Sliding door详解
    《图解CSS3核心技术与案例实战》——第3章 CSS3边框

  • 相关阅读:
    PHP调用WCF提供的方法
    关于git报 warning: LF will be replaced by CRLF in README.md.的警告的解决办法
    vue中引入mui报Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them的错误
    微信小程序报Cannot read property 'setData' of undefined的错误
    Vue那些事儿之用visual stuido code编写vue报的错误Elements in iteration expect to have 'v-bind:key' directives.
    关于xampp中无法启动mysql,Attempting to start MySQL service...的解决办法!!
    PHP的环境搭建
    新手PHP连接MySQL数据库出问题(Warning: mysqli_connect(): (HY000/1045): Access denied for user 'root'@'localhost' (using password: YES))
    手机号码、获得当前时间,下拉框,填写限制
    团队作业(五):冲刺总结
  • 原文地址:https://www.cnblogs.com/fsjohnhuang/p/5458573.html
Copyright © 2011-2022 走看看