Complex design pattern - overlapping transparent s

2019-07-10 04:07发布

问题:

I'm trying to create following shape.

Almost I tried to create this image by following way. In order create this Image using HTML and CSS. I tried to use following code.

.left1{
  float:left;
  transform: rotate(180deg);
}
.halfCircleRight1{
   height: 70px;
   width: 70px;
   border-top-right-radius: 10em;
   border-bottom-right-radius: 10em;
   background: #326d7d;       
}

.halfCoverTop1 {
   height: 35px;
   width: 35px;
   border-bottom-right-radius: 10em;
   background: #ffffff;
   
}

.halfCoverBottom1{
   height: 35px;
   width: 35px;
   border-top-right-radius: 10em;
   background: #ffffff;
}
.left{
  float:left;
}
.halfCircleRight{
   height: 70px;
   width: 70px;
   border-top-right-radius: 10em;
   border-bottom-right-radius: 10em;
   background: #b1a51f;       
}

.halfCoverTop {
   height: 35px;
   width: 35px;
   border-bottom-right-radius: 10em;
   background: #ffffff;
}

.halfCoverBottom{
   height: 35px;
   width: 35px;
   border-top-right-radius: 10em;
   background: #ffffff;
}
<div class="left">
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
 </div>
<div class="left">
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
 </div>
<div class="left">
  <div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
 </div>
<div class="left">
  <div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
<div class="halfCircleRight">
  <div class="halfCoverTop"></div>
  <div class="halfCoverBottom"></div>
</div>
 </div>
<div class="left1">
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
 </div>
<div class="left1">
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
 </div>
<div class="left1">
  <div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
 </div>
<div class="left1">
  <div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
<div class="halfCircleRight1">
  <div class="halfCoverTop1"></div>
  <div class="halfCoverBottom1"></div>
</div>
 </div>

But some where I'm going wrong to achieve my desires output.I'm not able to figure out my approach. Could any one can please help achieve my actual output.

回答1:

There are multiple possibilities to create this shape. Each one has its own pros and cons. You may decide which best suits your needs.

SVG Based Approach:

SVG is the recommneded and more appropriate way to create such shapes.

Step #1:

The idea is to draw a small component that is being repeated in your shape and then repeat it using SVG's patterns. We can use SVG's path element to create this shape and fill it with some color, gradient or pattern.

Only one attribute d is used to define shapes in path element. This attribute itself contains a number of short commands and few parameters that are necessary for those commands to work.

Below is the necessary code to create this shape:

<path d="M 0,.125
         Q .110,.114 .125,0
         A .125,.125 0 0 1 .125,.250
         Q .110,.136 0,.125" />

I've used 3 commands inside path element. Below is a brief description:

  • M command is used to define the starting point. It appears at the beginning and specify the point from where drawing should start.
  • Q command is used to draw curves.
  • A command is also used to draw curves.

Working Example:

body {
  background-color: #ececec;
}
svg {
  margin: 10px auto;
  display: block;
}
<svg width="170" height="170" viewBox="0 0 50 50">
    <path d="M 0,25
             Q 22,22 25,0
             A 25,25 0 0 1 25,50
             Q 22,28 0,25" fill="#aba219" fill-opacity="inherit" />

</svg>

Output Image:

Below is the output of first step:


Step #2:

Now we will create a pattern that will repeat this shape. After creating this we will be a bit more closer to the final output.

Consider the below code:

<defs>
    <pattern id="pattern1" x="0" y="0" width="25%" height="25%"
             patternUnits="objectBoundingBox"
             patternContentUnits="objectBoundingBox">
        <path id="tile" fill="inherit" fill-opacity="inherit"
              d="M 0,.125
                 Q .110,.114 .125,0
                 A .125,.125 0 0 1 .125,.250
                 Q .110,.136 0,.125" />
    </pattern>
</defs>

<rect x="0" y="0" width="200" height="200" fill="url(#pattern1)" />

Below is a brief description of above code:

  • SVG's <defs> element is used to define graphics/elements for later use. Objects defined inside defs are not drawn immediately on screen. They will be referenced by other parts of the code in future.
  • The <pattern> element defines a graphics object which can be redrawn at repeated x and y-coordinate intervals ("tiled") to cover an area. This pattern will be referenced by fill / stroke attributes of graphics elements.
  • <rect> element is used to draw rectangular area on screen. Notice the fill attribute used on this element. This attribute is referencing the pattern defined above in <defs> section. Now we are actually using this pattern to fill the rectangular area.

Working Example:

body {
  background-color: #ececec;
}
svg {
  margin: 0 auto;
  display: block;
}
<svg width="200" height="200" viewBox="0 0 200 200">
    <defs>
        <path id="tile" fill="inherit" fill-opacity="inherit"
              d="M 0,.125
                 Q .110,.114 .125,0
                 A .125,.125 0 0 1 .125,.250
                 Q .110,.136 0,.125" />

        <pattern id="pattern1" x="0" y="0" width="25%" height="25%"
                 patternUnits="objectBoundingBox"
                 patternContentUnits="objectBoundingBox">
            <use href="#tile" fill="#aba219" />
        </pattern>
    </defs>
    <rect x="0" y="0" width="200" height="200" fill="url(#pattern1)" />
</svg>

Output Image:

Below is the result till now:


Step #3:

Finally we will create two patterns and apply it on 2 different <rect> elements to create the final output.

Following code pattern will be used to create final output:

<defs>
    <path id="tile" d="..." />

    <pattern id="pattern1">
        <use href="#tile" fill="#aba219" />
    </pattern>
    <pattern id="pattern2" patternTransform="scale(-1)">
        <use href="#tile" fill="#023e54" />
    </pattern>
</defs>
<rect width="200" height="880" fill="url(#pattern1)" />
<rect width="200" height="200" fill="url(#pattern2)" />

Most of the code is similar as described above. However notice the use of <use> element. Instead of defining path element in each pattern element, we have defined it once and copying it in 2 other places with <use> element.

The <use> element takes nodes from within the SVG document, and duplicates them somewhere else.

Working Example:

body {
  background-color: #ececec;
}
svg {
  margin: 0 auto;
  display: block;
}
<svg width="190" height="190" viewBox="0 0 990 990">
    <defs>
        <path id="tile" fill="inherit" fill-opacity="inherit"
              d="M 0,.125
                 Q .110,.114 .125,0
                 A .125,.125 0 0 1 .125,.250
                 Q .110,.136 0,.125" />

        <pattern id="pattern1" x="0" y="0" width="25%" height="25%"
                 patternUnits="objectBoundingBox"
                 patternContentUnits="objectBoundingBox">
            <use href="#tile" fill="#aba219" />
        </pattern>

        <pattern id="pattern2" x="0" y="0" width="25%" height="25%"
                 patternUnits="objectBoundingBox"
                 patternContentUnits="objectBoundingBox"
                 patternTransform="scale(-1)">
            <use href="#tile" fill="#023e54" fill-opacity="0.7" />
        </pattern>
    </defs>

    <rect x="0" y="0" width="880" height="880" fill="url(#pattern1)" />
    <rect x="110" y="110" width="880" height="880" fill="url(#pattern2)" />
</svg>

Output Image:

Below is the final output image:


HTML/CSS Based Approach:

Although possible but I won't recommend this because a lot of elements will be required to create this shape which is won't be an efficient approach.

Working Example:

body {
  background-color: #ececec;
}
.tile-list {
  list-style: none;
  margin: 0 auto;
  width: 225px;
  padding: 0;
}

.tile-list li {
  display: flex;
}
.tile-list li:nth-child(even) {
  position: relative;
  padding-left: 25px;
  margin: -25px 0;
  z-index: 1;
}

.tile {
  border-radius: 100%;
  position: relative;
  overflow: hidden;
  height: 50px;
  width: 50px;
}
.tile .left {
  position: absolute;
  overflow: hidden;
  height: 50%;
  width: 50%;
  left: 0;
  top: 0;
}
.tile .left.bottom {
  bottom: 0;
  top: auto;
}
.tile .left::before {
  box-shadow: 0 0 0 10px #aba219;
  border-radius: 100%;
  position: absolute;
  overflow: hidden;
  content: '';
  height: 200%;
  width: 200%;
  left: -100%;
  top: -100%;
}
.tile .left.bottom::before {
  bottom: -100%;
  top: auto;
}
.tile .right {
  position: absolute;
  overflow: hidden;
  height: 100%;
  width: 100%;
  left: 50%;
  top: 0;
}
.tile .right::before {
  background-color: #aba219;
  position: absolute;
  height: 100%;
  content: '';
  width: 100%;
  left: -50%;
  top: 0;
}
.tile-list li:nth-child(even) .tile {
  transform: scale(-1);
}
.tile-list li:nth-child(even) .tile .right::before {
  background-color: rgb(2, 62, 84, 0.7);
}
.tile-list li:nth-child(even) .tile .left::before {
  box-shadow: 0 0 0 10px rgb(2, 62, 84, 0.7);
}
<ul class="tile-list">
  <li>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
  </li>
  <li>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
  </li>
  <li>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
  </li>
  <li>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
  </li>
  <li>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
  </li>
  <li>
    <div class="tile">
      <div class="left top"></div>
      <div class="left bottom"></div>
      <div class="right"></div>
    </div>
<div class="tile">
<div class="left top"></div>
<div class="left bottom"></div>
<div class="right"></div>
</div>
<div class="tile">
<div class="left top"></div>
<div class="left bottom"></div>
<div class="right"></div>
</div>
<div class="tile">
<div class="left top"></div>
<div class="left bottom"></div>
<div class="right"></div>
</div>
</li>
</ul>



回答2:

What about another idea using some SVG, pseudo-element and multiple background:

.box {
  margin:60px;
  width:450px;
  height:250px;
  background:
  url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="10 10 75 80" width="100"><path d="M50 10 C 100 10, 100 90, 50 90 C 50 65, 35 50, 10 50 C 35 50, 50 35, 50 10"  fill="rgb(177, 165, 31,0.8)"/></svg>') -50px -50px /100px 100px,
  url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-90 10 75 80" width="100"><path d="M50 10 C 100 10, 100 90, 50 90 C 50 65, 35 50, 10 50 C 35 50, 50 35, 50 10"  fill="%23326d7d"  transform="scale(-1,1)"/></svg>') 0px 0px/100px 100px;
  position:relative;
}
.box:before {
  content:"";
  position:absolute;
  top:-50px;
  height:50px;
  left:0;
  right:0;
  background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="10 10 75 80" width="100"><path d="M50 10 C 100 10, 100 90, 50 90 C 50 65, 35 50, 10 50 C 35 50, 50 35, 50 10"  fill="rgb(177, 165, 31,0.8)"/></svg>') 50px 0 /100px 100px;
}

.box:after {
  content:"";
  position:absolute;
  bottom:-50px;
  height:50px;
  left:0;
  right:0;
  background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-90 10 75 80" width="100"><path d="M50 10 C 100 10, 100 90, 50 90 C 50 65, 35 50, 10 50 C 35 50, 50 35, 50 10"  fill="%23326d7d"  transform="scale(-1,1)"/></svg>')0px -50px/100px 100px ;
}
.intern {
  height:100%;
  position:relative;
}
.intern:before {
  content:"";
  position:absolute;
  top:-50px;
  bottom:0;
  left:-50px;
  width:50px;
  background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="10 10 75 80" width="100"><path d="M50 10 C 100 10, 100 90, 50 90 C 50 65, 35 50, 10 50 C 35 50, 50 35, 50 10"  fill="rgb(177, 165, 31,0.8)"/></svg>') 0 0 /100px 100px;
}
.intern:after {
  content:"";
  position:absolute;
  top:0;
  bottom:-50px;
  right:-50px;
  width:50px;
  background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-90 10 75 80" width="100"><path d="M50 10 C 100 10, 100 90, 50 90 C 50 65, 35 50, 10 50 C 35 50, 50 35, 50 10"  fill="%23326d7d"  transform="scale(-1,1)"/></svg>')-50px 0/100px 100px;
}
<div class="box">
<div class="intern"></div>
</div>

UPDATE

Here is another idea without the use of SVG and only CSS (I will rely on radial-gradient):

.container {
  position:relative;
  width:400px;
  z-index:0;
}
.bottom {
  position:absolute;
  z-index:-1;
  top:0;
  left:0;
  transform:translate(50px,50px);
}

.top    >div,
.bottom >div{
  width:100px;
  height:100px;
  border-radius:50%;
  display:inline-block;
  background-size:100% 50%;
  background-position:top,bottom;
  background-repeat:no-repeat;
}
.top    >div {
  background-image:
    radial-gradient(circle at top left,   transparent 44%, rgb(177, 165, 31,0.8) 44.5%),
    radial-gradient(circle at bottom left,transparent 44%, rgb(177, 165, 31,0.8) 44.5%);
}
.bottom >div {
  background-image:
    radial-gradient(circle at top right,   transparent 44%, #326d7d 44.5%),
    radial-gradient(circle at bottom right,transparent 44%, #326d7d 44.5%);
}
<div class="container"> 
<div class="top">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<div class="bottom">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
</div>