Styling a funnel stack layout using native CSS and

2019-06-17 15:45发布

I want to show the data like funnel stack as illustrated below.

enter image description here

I was able to create the taper using borders, for example:

<div class="taper"></div>

and using the following CSS:

.taper {
    width: 200px;
    height: 0px;
    border-color: lightgray transparent;
    border-style: solid;
    border-width: 50px 25px 0 25px;
} 

Of course, the idea would be to wrap this div.taper in a container, add other elements and position them as needed, a bit of work but doable.

However, I don't necessarily know how many lines (levels, 7 in this example) will be needed and I don't really want to do a lot of math to determine the width of each taper and so on.

If there a more bullet-proof way of doing this?

I don't want a JavaScript/jQuery based solution (trying to keep this lightweight) and would prefer to avoid background images (I may want to skin/customize the colors later and don't want to bother with image files).

Fiddle reference: http://jsfiddle.net/audetwebdesign/fBax3/

Browser support: modern browsers are fine, legacy support, as long as it degrades nicely.

5条回答
萌系小妹纸
2楼-- · 2019-06-17 16:17

Ryan,

Thanks for your code example! I took your example and changed it a bit to reflect my project needs. Maybe someone will find this helpful.

body {
  font-family: Lato, Arial, Helvetica, sans-serif;
}
.center-text {
  text-align: center;
  margin: 0px auto;
}
.funnel {
  width: 750px;
  margin: 0 auto;
}
ul.one {
  margin: 40px 278px;
  padding: 0;
  list-style: none;
  text-align: center;
}
.one .funnel-top {
  position: absolute;
  top: -7px;
  left: -199px;
  z-index: 20;
  width: 599px;
  height: 14px;
  background: #919eb1;
  border-radius: 100%;
}
.one .funnel-bottom {
  position: absolute;
  bottom: -7px;
  left: -20px;
  z-index: 20;
  width: 240px;
  height: 16px;
  background: #273445;
  border-radius: 100%;
}
.one li {
  font-size: 16px;
  line-height: 70px;
  height: 70px;
  width: 200px;
  position: relative;
  background: #ccc;
  color: #ffffff;
  font-weight: bold;
}
.one li span {
  background: rgba(255, 255, 255, 0.3);
  padding: 5px 8px;
  border-radius: 4px;
  margin-left: 15px;
}
.one li:before {
  content: "";
  position: absolute;
  z-index: 10;
  left: 0%;
  margin-left: -30px;
  width: 30px;
  border-top: 70px solid #ccc;
  border-left: 30px solid transparent;
}
.one li:after {
  content: "";
  position: absolute;
  z-index: 10;
  right: 0%;
  margin-left: 30px;
  width: 30px;
  border-top: 70px solid #ccc;
  border-right: 30px solid transparent;
}
.one li:nth-child(1) {
  background: #919eb1;
}
.one li:nth-child(1):before,
.one li:nth-child(1):after {
  border-top-color: #919eb1;
}
.one li:nth-child(1):before {
  width: 200px;
  margin-left: -200px;
}
.one li:nth-child(1):after {
  width: 200px;
  margin-right: -200px;
}
.one li:nth-child(2) {
  background: #8491a5;
}
.one li:nth-child(2):before,
.one li:nth-child(2):after {
  border-top-color: #8491a5;
}
.one li:nth-child(2):before {
  width: 170px;
  margin-left: -170px;
}
.one li:nth-child(2):after {
  width: 170px;
  margin-right: -170px;
}
.one li:nth-child(3) {
  background: #778599;
}
.one li:nth-child(3):before,
.one li:nth-child(3):after {
  border-top-color: #778599;
}
.one li:nth-child(3):before {
  width: 140px;
  margin-left: -140px;
}
.one li:nth-child(3):after {
  width: 140px;
  margin-right: -140px;
}
.one li:nth-child(4) {
  background: #6d7b8f;
}
.one li:nth-child(4):before,
.one li:nth-child(4):after {
  border-top-color: #6d7b8f;
}
.one li:nth-child(4):before {
  width: 110px;
  margin-left: -110px;
}
.one li:nth-child(4):after {
  width: 110px;
  margin-right: -110px;
}
.one li:nth-child(5) {
  background: #606f84;
}
.one li:nth-child(5):before,
.one li:nth-child(5):after {
  border-top-color: #606f84;
}
.one li:nth-child(5):before {
  width: 80px;
  margin-left: -80px;
}
.one li:nth-child(5):after {
  width: 80px;
  margin-right: -80px;
}
.one li:nth-child(6) {
  background: #536075;
}
.one li:nth-child(6):before,
.one li:nth-child(6):after {
  border-top-color: #536075;
}
.one li:nth-child(6):before {
  width: 50px;
  margin-left: -50px;
}
.one li:nth-child(6):after {
  width: 50px;
  margin-right: -50px;
}
ul.two {
  margin: 40px 278px;
  padding: 0;
  list-style: none;
  text-align: center;
}
.two .funnel-top {
  position: absolute;
  top: -7px;
  left: -199px;
  z-index: 20;
  width: 599px;
  height: 14px;
  background: #1b99e6;
  border-radius: 100%;
}
.two .funnel-bottom {
  position: absolute;
  bottom: -7px;
  left: -20px;
  z-index: 20;
  width: 240px;
  height: 16px;
  background: #003352;
  border-radius: 100%;
}
.two li {
  font-size: 16px;
  line-height: 70px;
  height: 70px;
  width: 200px;
  position: relative;
  background: #ccc;
  color: #ffffff;
  font-weight: bold;
}
.two li span {
  background: rgba(255, 255, 255, 0.3);
  padding: 5px 8px;
  border-radius: 4px;
  margin-left: 15px;
}
.two li:before {
  content: "";
  position: absolute;
  z-index: 10;
  left: 0%;
  margin-left: -30px;
  width: 30px;
  border-top: 70px solid #ccc;
  border-left: 30px solid transparent;
}
.two li:after {
  content: "";
  position: absolute;
  z-index: 10;
  right: 0%;
  margin-left: 30px;
  width: 30px;
  border-top: 70px solid #ccc;
  border-right: 30px solid transparent;
}
.two li:nth-child(1) {
  background: #1b99e6;
}
.two li:nth-child(1):before,
.two li:nth-child(1):after {
  border-top-color: #1b99e6;
}
.two li:nth-child(1):before {
  width: 200px;
  margin-left: -200px;
}
.two li:nth-child(1):after {
  width: 200px;
  margin-right: -200px;
}
.two li:nth-child(2) {
  background: #148ad3;
}
.two li:nth-child(2):before,
.two li:nth-child(2):after {
  border-top-color: #148ad3;
}
.two li:nth-child(2):before {
  width: 170px;
  margin-left: -170px;
}
.two li:nth-child(2):after {
  width: 170px;
  margin-right: -170px;
}
.two li:nth-child(3) {
  background: #117fc3;
}
.two li:nth-child(3):before,
.two li:nth-child(3):after {
  border-top-color: #117fc3;
}
.two li:nth-child(3):before {
  width: 140px;
  margin-left: -140px;
}
.two li:nth-child(3):after {
  width: 140px;
  margin-right: -140px;
}
.two li:nth-child(4) {
  background: #0b75b6;
}
.two li:nth-child(4):before,
.two li:nth-child(4):after {
  border-top-color: #0b75b6;
}
.two li:nth-child(4):before {
  width: 110px;
  margin-left: -110px;
}
.two li:nth-child(4):after {
  width: 110px;
  margin-right: -110px;
}
.two li:nth-child(5) {
  background: #006bac;
}
.two li:nth-child(5):before,
.two li:nth-child(5):after {
  border-top-color: #006bac;
}
.two li:nth-child(5):before {
  width: 80px;
  margin-left: -80px;
}
.two li:nth-child(5):after {
  width: 80px;
  margin-right: -80px;
}
.two li:nth-child(6) {
  background: #005f98;
}
.two li:nth-child(6):before,
.two li:nth-child(6):after {
  border-top-color: #005f98;
}
.two li:nth-child(6):before {
  width: 50px;
  margin-left: -50px;
}
.two li:nth-child(6):after {
  width: 50px;
  margin-right: -50px;
}
<br />

<div class="funnel leads estimated">
  <h2 class="center-text">Estimated 100 Day Lead Conversion</h2>
  <ul class="one">
    <li>
      <div class="funnel-top"></div>
      1574<span>Contacts</span>
    </li>
    <li>203<span>MQL2</span>
    </li>
    <li>112<span>MQL2</span>
    </li>
    <li>57<span>SAL</span>
    </li>
    <li>11<span>SQL</span>
    </li>
    <li>
      <div class="funnel-bottom"></div>
      4<span>Wins</span>
    </li>
  </ul>
</div>

<div class="funnel leads estimated">
  <h2 class="center-text">Actual 100 Day Lead Conversion</h2>
  <ul class="two">
    <li>
      <div class="funnel-top"></div>
      1574<span>Contacts</span>
    </li>
    <li>203<span>MQL2</span>
    </li>
    <li>112<span>MQL2</span>
    </li>
    <li>57<span>SAL</span>
    </li>
    <li>11<span>SQL</span>
    </li>
    <li>
      <div class="funnel-bottom"></div>
      4<span>Wins</span>
    </li>
  </ul>
</div>

View on JSFiddle

查看更多
霸刀☆藐视天下
3楼-- · 2019-06-17 16:20

Here's another take on it, this version is a bit more responsive: https://jsfiddle.net/ehynds/j3fL6hof

.funnel {
  list-style-type: none;
  margin: 0;
  padding: 0;
  text-align: center;
  color: #fff;
  background-color: #fff;
}

li {
  padding: 10px 5px;
  margin: 0;
  background-color: #409ca9;
  margin-bottom: 5px;
  position: relative;
  overflow: hidden;
}

div:last-child {
  font-size: 36px
}

li:last-child {
  background-color: #a5c13f;
}

li:before,
li:after {
  content: '';
  position: absolute;
  top: 0;
  height: 0;
  border-bottom: 90px solid #fff;
}

li:before {
  left: 0;
  border-right: 27px solid transparent;
  border-left: 0;
}

li:after {
  right: 0;
  border-left: 27px solid transparent;
  border-right: 0;
}

li:nth-child(1):before,
li:nth-child(1):after {
  width: 0;
}

li:nth-child(2):before,
li:nth-child(2):after {
  width: 25px;
}

li:nth-child(3):before,
li:nth-child(3):after {
  width: 50px;
}

li:nth-child(4):before,
li:nth-child(4):after {
  width: 75px;
  height: 100%;
  border: 0;
  background-color: #fff;
}
<ul class="funnel">
  <li>
    <div>First Segment</div>
    <div>12,345</div>
  </li>
  <li>
    <div>Second Segment</div>
    <div>2,345</div>
  </li>
  <li>
    <div>Third Segment</div>
    <div>345</div>
  </li>
  <li>
    <div>Fourth Segment</div>
    <div>45</div>
  </li>
</ul>

查看更多
Animai°情兽
4楼-- · 2019-06-17 16:26

For those looking for a funnel with different colors for each layer in the stack:

enter image description here

http://jsfiddle.net/D9GLr/

HTML:

<ul>
    <li>1,234,567,890</li>
    <li>234,567,890</li>
    <li>23,456,789</li>
    <li>2,345,678</li>
    <li>234,567</li>
</ul>

CSS:

ul { 
    margin: 0 200px; padding: 0; 
    list-style: none; 
    text-align: center;
}

li {
    font-size:14px;
    line-height:30px;
    height:30px;
    width:200px;
    position:relative;
    background:#ccc;
    border-bottom:1px solid #fff;
}

li:before { 
    content: "";
    position: absolute;
    z-index: 10;
    left: 0%;
    margin-left: -30px;
    width:30px;
    border-top: 30px solid #ccc;
    border-left: 30px solid transparent;
}
li:after { 
    content: "";
    position: absolute;
    z-index: 10;
    right: 0%;
    margin-left: 30px;
    width:30px;
    border-top: 30px solid #ccc;
    border-right: 30px solid transparent;
}

li:nth-child(1) { background:#ddd; }
li:nth-child(1):before,
li:nth-child(1):after { border-top-color:#ddd; }
li:nth-child(1):before { width:200px; margin-left: -200px; }
li:nth-child(1):after  { width:200px; margin-right:-200px; }

li:nth-child(2) { background:#bbb; }
li:nth-child(2):before,li:nth-child(2):after { border-top-color:#bbb; }
li:nth-child(2):before { width:170px; margin-left: -170px; }
li:nth-child(2):after  { width:170px; margin-right:-170px; }

li:nth-child(3) { background:#999; }
li:nth-child(3):before,
li:nth-child(3):after { border-top-color:#999; }
li:nth-child(3):before { width:140px; margin-left: -140px; }
li:nth-child(3):after  { width:140px; margin-right:-140px; }

li:nth-child(4) { background:#777; }
li:nth-child(4):before,
li:nth-child(4):after { border-top-color:#777; }
li:nth-child(4):before { width:110px; margin-left: -110px; }
li:nth-child(4):after  { width:110px; margin-right:-110px; }

li:nth-child(5) { background:#555; }
li:nth-child(5):before,
li:nth-child(5):after { border-top-color:#555; }
li:nth-child(5):before { width:80px; margin-left: -80px; }
li:nth-child(5):after  { width:80px; margin-right:-80px; }
查看更多
爷的心禁止访问
5楼-- · 2019-06-17 16:35

I like the approach of dividing it into few divs. See the code here

I have to add code so an example:

<div class="cont">
    <div class="taper-left"></div>
    <div class="taper-center">123,456,789</div>
    <div class="taper-right"></div>
</div>

and the CSS:

.taper-right {
width: 25px;
height: 0px;
border-color: lightgray transparent;
border-style: solid;
border-width: 50px 25px 0 0px;
float: left;
}

.taper-left {
width: 25px;
height: 0px;
border-color: lightgray transparent;
border-style: solid;
border-width: 50px 0px 0px 25px;
float: left;
}

.taper-center {
width: 200px;
height: 34px;
border-color: lightgray transparent;
border-style: solid;
background-color: lightgray transparent;
background-color: lightgray;
float: left;
text-align: center;
padding-top: 10px;
}
查看更多
对你真心纯属浪费
6楼-- · 2019-06-17 16:36

TL;DR : see the example at http://jsfiddle.net/97Yr6/


A way to create a funnel stack is with pseudoelements: with this basic markup

<ul>
    <li>1,234,567,890 <span>Tooltip: 0</span></li>
    <li>234,567,890 <span>Tooltip: 0</span></li>    
    <li>23,456,789</li>    
    <li>2,345,678 <span>Tooltip: 0</span></li>    
    <li>234,567</li>  
    <li>23,567  <span>Tooltip: 0</span></li>
    <li>4,567<span>Tooltip: 0</span></li>    
    <li>789</li>    
    <li>23 <span>Tooltip: 0</span></li>
    <li>4 <span>Tooltip: 0</span></li>    
</ul>

we could create the funnel using borders, so we can draw a kind of trapezoid as a background in this way:

ul { 
    position: relative; 
    overflow: hidden; 
    font: 14px Arial; 
    margin: 0; padding: 0; 
    list-style: none; 
    text-align: center; 
}


ul:before { 
    content: "";
    position: absolute;
    z-index: -1;
    left: 50%;
    margin-left: -120px;
    width: 0;
    border-top: 800px solid #ccc;
    border-left: 120px solid #fff;
    border-right: 120px solid #fff;
}

The <ul> is 100% wide, so we could give it a text-align: center and all the amounts are properly centered

Then the space between elements could be obtained as well with pseudoelements again:

li:after,li:before {
   content: "";
   display: block;
   height: 0.4em;
   background: #fff;
   width: 100%;
}
li:before { border-top: 1px dotted #ccc }
li:first-child:before { border: 0; }

while the tooltip text could be positioned (the <li> needs to have position: relative defined), trying to properly adjust both left and margin-left properties (especially for lower screen resolution, but you may use mediaqueries for this purpose), e.g.

li span {
    position: absolute;
    left: 60%;
    white-space: nowrap;
    margin-left: 100px;
}

li:nth-child(2) span { left: 59%; }
li:nth-child(3) span { left: 58% }
li:nth-child(4) span { left: 57% }
li:nth-child(5) span { left: 56% }
li:nth-child(6) span { left: 55% }
li:nth-child(7) span { left: 54% }
li:nth-child(8) span { left: 53% }
li:nth-child(9) span { left: 52% }
li:nth-child(10) span { left: 51% }

basically this example may work even on IE8 if you change each :nth-child with the adjacency selector (e.g. li + li + li + ... + span )

Hope it could be helpful.

查看更多
登录 后发表回答