Creating a CSS double border line with a step in t

2019-02-12 11:37发布

问题:

I'm trying to achieve this(Pic below) with strictly CSS and HTML for this header to be displayed on mobile devices. I was able to get it done, although I believe my way of doing this might be wrong. I'm adding these in two containers and getting them aligned and connected just right, is just almost impossible.

Here's my CSS:

#shape1:before{
  position: absolute;
  bottom: 30px; left: -4px;
  content: '';
  height: 15px;
  width: 41%;
  border-bottom: 3.5px solid #000000;
  border-right: 4.5px solid #000000;
  transform: skew(-45deg);
}
#shape1:after{
  position: absolute;
  content: '';
  bottom: 24px; left: 0px;
  height: 16px;
  width: 41%;
  border-bottom: 3.5px solid #000000;
  border-right: 4.5px solid #000000;
  transform: skew(-45deg);
  z-index: -1;
}
#shape1{
  position: relative;
  height: 79.5px;
  width: 400px;
  z-index: -1;
}
#shape:before{
  position: absolute;
  content: '';
  right: 0px;
  width: 57.5%;
  top: 31.2px;
  z-index: -1;
  border-bottom: 3px solid #000000;
  box-shadow: 1px 2px 5px rgba(0,0,0, .3);
}
#shape:after{
  position: absolute;
  content: '';
  top: 36px;
  width: 56.5%;
  z-index: -1;
  right: 0px;
  border-bottom: 3px solid #000000;
  box-shadow: 1px 3px 5px rgba(0,0,0, .3);
}
#shape {
  height: 71px;
  width: 400px;
}

Any link or shared knowledge would be appreciated. I just can't seem to find anything on this at the moment. I do also wan't to add some shadow in this and that's why you'll find some some box-shadow code in there, but just haven't got to it 100% yet.

回答1:

Using CSS Transforms:

To achieve the double border using CSS without any problems in getting them aligned properly, skew transforms are the best bet as we can always fix the points about which the transform happens (thus eliminating any potential problems with alignment). However, we cannot use double border with this approach because skew transformation would cause the border lines on the angled sides to look a lot closer to each other than on top and bottom. To overcome this, we have to use an extra child element.

The output is perfectly responsive and this can be verified by viewing the snippet output in full page.

.double-outer-border {
  position: relative;
  border-top: 1px solid;
  height: 100px;
  width: 100%;
  overflow: hidden;
}
.double-outer-border:before,
.double-outer-border:after,
.double-inner-border:before,
.double-inner-border:after {
  position: absolute;
  content: '';
  height: 20px;
  bottom: 0px;
  width: 50%;
  transform: skew(-45deg);
}
.double-outer-border:before {
  left: -2px;
}
.double-outer-border:after {
  right: -2px;
}
.double-inner-border:before {
  left: -4px;
  bottom: 4px;
}
.double-inner-border:after {
  right: 0px;
  bottom: 4px;
}
.double-outer-border:before,
.double-inner-border:before {
  border-bottom: 3px solid;
  border-right: 4px solid;
  transform-origin: right bottom;
}
.double-outer-border:after,
.double-inner-border:after {
  border-top: 3px solid;
  border-left: 4px solid;
  transform-origin: left bottom;
  box-shadow: inset 2px 2px 2px rgba(0, 0, 0, .3);
}
<div class='double-outer-border'>
  Some content
  <div class='double-inner-border'></div>
</div>


Using CSS Gradients:

The below is a very complex approach compared to the earlier one but I am posting it here just to give some different ideas. The whole double border with a slant can be achieved using linear-gradients (and a bit of transforms also). Though this produces the expected output, I wouldn't recommend it. Use this approach only to get some ideas on what all can be done with gradients :)

.double-border {
  position: relative;
  height: 100px;
  width: 100%;
  border-top: 1px solid;
  overflow: hidden;
}
.double-border:before {
  position: absolute;
  content: '';
  height: 100%;
  width: calc(50% + 10px);
  left: -10px;
  top: 0px;
  background: linear-gradient(to right, black 99.9%, transparent 99.9%), linear-gradient(to right, black 99.9%, transparent 99.9%);
  background-repeat: no-repeat;
  background-position: -4.5px 97px, -9px 91px;
  background-size: 100% 3px;
}
.double-border:after {
  position: absolute;
  content: '';
  height: 100%;
  width: calc(50% + 10px);
  left: -10px;
  top: 0px;
  background: linear-gradient(to right, black 99.9%, transparent 99.9%), linear-gradient(to right, black 99.9%, transparent 99.9%), linear-gradient(to right, rgba(0,0,0,0.3) 99.9%, transparent 99.9%), linear-gradient(to right, rgba(0,0,0,0.3) 99.9%, transparent 99.9%);
  background-repeat: no-repeat;
  background-position: -7.5px 75px, -9px 81px, -8.5px 77px, -10px 83px;
  background-size: 100% 3px;
  transform: scaleX(-1);
  transform-origin: right;
}
.slanted-border {
  position: absolute;
  height: 25px;
  width: 25px;
  bottom: 3px;
  left: 50%;
  transform: translateX(-50%) rotate(-45deg);
  background: linear-gradient(to right, black 99%, transparent 99%), linear-gradient(to right, black 95%, transparent 95%), linear-gradient(to right, rgba(0,0,0,0.3) 99%, transparent 99%), linear-gradient(to right, rgba(0,0,0,0.3) 95%, transparent 95%);
  background-repeat: no-repeat;
  background-position: 0px 11px, -2px 17px, 0px 13px, -2px 19px;
  background-size: 100% 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='double-border'>
  Some Content
  <div class='slanted-border'></div>
</div>


Using SVG:

Generally the easiest method to draw such shapes or complex lines would be SVG (which also has the benefit of being responsive and can adapt to any change in dimensions) but there are a few drawbacks of using SVG for this one:

  • If the height of your header is constant and only the width changes based on the device then the SVG will have to stretch/shrink to fit the container (depending on the original dimensions) and this would make the slanted line in the middle either look crunched (or) elongated. (View the snippet in full page mode.)
  • The stroke would also get scaled by default in SVG. This can be avoided by setting the vector-effect attribute to non-scaling-stroke but at present this property is not supported by IE and thus this solution is not cross-browser compatible.

path {
  stroke: black;
  fill: none;
  stroke-width: 2;
}
svg {
  height: 100px;
  width: 100%;
  border-top: 1px solid;
}
<svg viewBox='0 0 500 100' preserveaspectratio='none'>
  <path d='M0,98 240,98 260,75 500,75' vector-effect='non-scaling-stroke'/>
  <path d='M0,94 237.5,94 257.5,71 500,71' vector-effect='non-scaling-stroke'/>
</svg>



回答2:

I put together a responsive example on codepen, using 50% widths for the two containers. These could be changed accordingly. Unfortunately in a responsive environment anything other than an exact width in pixels will result in a varying width for the slanted portion of the line, as I'm sure you've found out.

#shape1:before {
  position: absolute;
  bottom: 38.5px;
  left: -10px;
  content: '';
  height: 15px;
  width: 100%;
  border-bottom: 3.5px solid #000000;
  border-right: 4.5px solid #000000;
  transform: skew(-45deg);
  background-color: white;
}
#shape1:after {
  position: absolute;
  content: '';
  bottom: 33px;
  left: -10px;
  height: 16px;
  width: 100%;
  border-bottom: 3.5px solid #000000;
  border-right: 4.5px solid #000000;
  transform: skew(-45deg);
  z-index: -1;
  background-color: white;
}
#shape1 {
  position: relative;
  height: 79.5px;
  width: 50%;
  z-index: -1;
}
#shape:before {
  position: absolute;
  content: '';
  right: 0px;
  width: 50%;
  top: 31.2px;
  z-index: -1;
  border-bottom: 3px solid #000000;
  box-shadow: 1px 2px 5px rgba(0, 0, 0, .3);
}
#shape:after {
  position: absolute;
  content: '';
  top: 36px;
  width: 50%;
  z-index: -1;
  right: 0px;
  border-bottom: 3px solid #000000;
  box-shadow: 1px 3px 5px rgba(0, 0, 0, .3);
}
#shape {
  height: 71px;
  width: 50%;
}
<div id="shape1"></div>
<div id="shape"></div>



回答3:

I'm not sure CSS is the best way to accomplish this. Personally, if I wanted to display the connected double lines you're showing, I would use SVG. But putting that aside, here's a simple CSS solution.

This method uses CSS borders, relative positioning, transform and inline-block. It's also responsive (along the x-axis).

Getting all three lines to connect smoothly is not an easy task (as you noted). Because of the precision required for alignment, you will likely have to tweak several values for this to work on your site. Not sure it's all worth it, but if an image format is not an option, I hope this helps.

HTML

<div id="container">
    <div id="left-line"></div>
    <div id="center-line"></div>
    <div id="right-line"></div>
</div>

CSS

#container {
    border-top-style: solid;
    border-top-width: 1px;
    border-top-color: black;
    width: 100%;
    }

#left-line {
    display: inline-block;
    width: 45%;
    height: 100px;
    border-bottom-color: black;
    border-bottom-style: double;
    border-bottom-width: 11px;
    }

#right-line {
    display: inline-block;
    width: 45%;
    height: 100px;
    border-bottom-color: black;
    border-bottom-style: double;
    border-bottom-width: 12px;
    position: relative;
    bottom: 18px;
    left: -15px;
    }

#center-line {
    display: inline-block;
    width: 20px;
    height: 36px;
    border-left-color: black;
    border-left-style: double;
    border-left-width: 11px;
    position: relative;
    left: -2px;
    bottom: -11px;

    -ms-transform: rotate(55deg);
    -webkit-transform: rotate(55deg);
    transform: rotate(55deg);
}

@media screen and (max-width: 500px) {
    #left-line { width: 40%; }
    #right-line { width: 40%; }
}

@media screen and (max-width: 400px) {
    #left-line { width: 35%; }
    #right-line { width: 35%; }
}

@media screen and (max-width: 300px) {
    #center-line { display: none; }
    #right-line { display: none; }
    #left-line { width: 100%; }
}

The code above renders this:

DEMO: http://jsfiddle.net/o39o17tv/7/ (re-size window for effect)

By the way, the alignment issue becomes less problematic if you use a solid line:

DEMO: http://jsfiddle.net/o39o17tv/8/



回答4:

Double skewed border

Note Would recommend using SVG for this.

CSS:

  • one element
  • two pseudo elements

Used a lot of calc() with percentage values to get it to be fully responsive.
Used a lot of border-style double since this seemed like the easiest way render the borders.
The one element that is skewed is an absolute positioned element with a white background.
So you will probably need to to have a solid color background.

.extra-border {
  position: relative;
  border-bottom: 11px double black;
  border-top: 3px solid black;
  height: 150px;
  width: 100%;
  box-sizing: border-box;
}
.extra-border::before {
  content: "";
  position: absolute;
  display: inline-block;
  width: 50%;
  height: 15%;
  background-color: white;
  bottom: -11px;
  right: 0;
  border-top: 11px double black;
  border-bottom: 11px solid transparent;
}
.extra-border::after {
  content: "";
  position: absolute;
  display: inline-block;
  background-color: white;
  width: 20px;
  height: calc(20% + 19px);
  border-left: 13px double black;
  right: calc(50% - 11px);
  bottom: -20px;
  transform-origin: center center;
  transform: rotate(45deg);
}
<div class="extra-border"></div>