Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting proper perspective for child elements on a 3d plane in CSS

I have an SVG hex grid tilted at a 45 degree angle. On individual hexes, I would like to place images (represented by the red rectangles) that appear to be standing upright respective to the plane of the grid. The images/rectangles don't necessarily have to be at a full 90 degrees, but I'm having the hardest time getting them to have any perspective that is even a little different from the plane.

Is there a way to unset the perspective for child elements or rework the CSS transforms somehow to make this look right?

Code

.display {
    animation: displayFlicker 100ms cubic-bezier(.37, 0, .41, 1.74) 100ms 1 normal forwards;
    -webkit-animation: displayFlicker 100ms cubic-bezier(.37, 0, .41, 1.74) 100ms 1 normal forwards;
    background: #000;
    display: block;
    border-left: 0.25rem solid #000;
    border-right: 0.25rem solid #000;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    height: 480px;
    overflow: hidden;
    width: 1096px;
}
#hexGrid {
    box-sizing: border-box;
    -moz-box-sizing: border-box;    
    display: block;
    height: 100%;
    -webkit-transform: perspective(44vw) rotateX(45deg) scale3d(1.6, 1.6, 1.6); 
    -moz-transform: perspective(44vw) rotateX(45deg) scale3d(1.6, 1.6, 1.6);    
    -ms-transform: perspective(44vw) rotateX(45deg) scale3d(1.6, 1.6, 1.6); 
    -o-transform: perspective(44vw) rotateX(45deg) scale3d(1.6, 1.6, 1.6);  
    transform: perspective(44vw) rotateX(45deg) scale3d(1.6, 1.6, 1.6);
    transform-style: preserve-3d;
    width: 100%;
}
.hexContainer {
    outline: none;
    transform-style: preserve-3d;
}
.hex {
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    display: inline-block;
    height: 4.4vmin;
    opacity: 1;
    outline: none;
    position: relative;
    stroke: #0CF;
    stroke-width: 0.0625rem;
    transform: scale3d(1, 1, 1);
    transition: all linear 300ms;
    width: 8vmin;
}
.hex.open {
    fill: rgba(0, 204, 255, 0.3);
}
.hex.blocked {
    fill: url(#blockedHexPattern);
    fill-opacity: 0.3;
}
.hexContainer:focus .open, .hexContainer:hover .open {
    cursor: pointer;
    fill: rgba(0, 204, 255, 0.8);
    outline: none;
}
.hexContainer:focus .blocked, .hexContainer:hover .blocked {
    cursor: pointer;
    fill: url(#blockedHexPattern);
    fill-opacity: 1;
    outline: none;
}
.hexContainer:focus .occupied, .hexContainer:hover .occupied {
    cursor: pointer;
    fill: rgba(50, 50, 50, 0.8);
    outline: none;
}
.hexContainer:focus .open, .hexContainer:focus .open.unblock {
    transform-origin: 50% 0%;
}
.hexContainer:focus .blocked {
    opacity: 1; 
    transform-origin: 50% 0%;
}
.hexContainer.active .open {
    fill: rgba(0, 204, 255, 0.8);
    opacity: 1; 
}
#blockedHexPattern line {
    stroke: #0CF;
    stroke-width: 0.0625rem;
}
#hexGrid .rect {
    transform: rotateX(0deg);   
}
<div id="stationMap" class="display">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="55 -30 360 360" id="hexGrid">
    <defs>
        <pattern x="0" y="0" height="10" width="10" patternUnits="userSpaceOnUse" id="blockedHexPattern">
            <line x1="0" y1="10" x2="10" y2="0"></line>
        </pattern>
    </defs>
    <a id="hex0-0" class="hexContainer">
        <polygon class="hex open" points="81.96152422706632,45 55.98076211353316,60 30,45 30.000000000000004,14.999999999999996 55.98076211353315,0 81.96152422706632,14.999999999999986"></polygon>
    </a>
    <a id="hex0-2" class="hexContainer">
        <polygon class="hex blocked" points="185.88457268119896,45 159.9038105676658,60 133.92304845413264,45 133.92304845413264,14.999999999999996 159.9038105676658,0 185.88457268119896,14.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex0-6" class="hexContainer">
        <polygon class="hex blocked" points="393.7306695894642,45 367.749907475931,60 341.76914536239786,45 341.76914536239786,14.999999999999996 367.749907475931,0 393.7306695894642,14.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex0-7" class="hexContainer">
        <polygon class="hex blocked" points="445.6921938165305,45 419.71143170299734,60 393.7306695894642,45 393.7306695894642,14.999999999999996 419.71143170299734,0 445.6921938165305,14.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex1-0" class="hexContainer">
        <polygon class="hex open" points="55.98076211353316,90 30.000000000000004,105 4.01923788646684,90 4.019237886466843,60 29.999999999999993,45 55.98076211353315,59.999999999999986"></polygon>
        <rect class="rect" fill="red" x="5" y="67.5" width="50" height="40"/>
    </a>
    <a id="hex1-3" class="hexContainer">
        <polygon class="hex blocked" points="211.8653347947321,90 185.88457268119893,105 159.90381056766577,90 159.90381056766577,60 185.88457268119893,45 211.8653347947321,59.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex1-4" class="hexContainer">
        <polygon class="hex open" points="263.82685902179844,90 237.84609690826525,105 211.8653347947321,90 211.8653347947321,60 237.84609690826525,45 263.8268590217984,59.999999999999986"></polygon>
    </a>
    <a id="hex1-5" class="hexContainer">
        <polygon class="hex open" points="315.7883832488647,90 289.80762113533154,105 263.8268590217984,90 263.8268590217984,60 289.80762113533154,45 315.7883832488647,59.999999999999986"></polygon>
    </a>
    <a id="hex1-6" class="hexContainer">
        <polygon class="hex open" points="367.749907475931,90 341.76914536239786,105 315.7883832488647,90 315.7883832488647,60 341.76914536239786,45 367.749907475931,59.999999999999986"></polygon>
    </a>
    <a id="hex1-7" class="hexContainer">
        <polygon class="hex open" points="419.71143170299734,90 393.7306695894642,105 367.749907475931,90 367.749907475931,60 393.7306695894642,45 419.71143170299734,59.999999999999986"></polygon>
        <rect class="rect" fill="red" x="369" y="67.5" width="50" height="40"/>
    </a>
    <a id="hex2-0" class="hexContainer">
        <polygon class="hex open" points="81.96152422706632,134.99999999999997 55.98076211353316,150 30,134.99999999999997 30.000000000000004,104.99999999999999 55.98076211353315,89.99999999999999 81.96152422706632,104.99999999999997"></polygon>
    </a>
    <a id="hex2-2" class="hexContainer">
        <polygon class="hex blocked" points="185.88457268119896,134.99999999999997 159.9038105676658,150 133.92304845413264,134.99999999999997 133.92304845413264,104.99999999999999 159.9038105676658,89.99999999999999 185.88457268119896,104.99999999999997" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex2-3" class="hexContainer">
        <polygon class="hex open" points="237.84609690826525,134.99999999999997 211.8653347947321,150 185.88457268119893,134.99999999999997 185.88457268119893,104.99999999999999 211.8653347947321,89.99999999999999 237.84609690826525,104.99999999999997"></polygon>
    </a>
    <a id="hex2-4" class="hexContainer">
        <polygon class="hex open" points="289.80762113533154,134.99999999999997 263.8268590217984,150 237.84609690826522,134.99999999999997 237.84609690826522,104.99999999999999 263.8268590217984,89.99999999999999 289.80762113533154,104.99999999999997"></polygon>
    </a>
    <a id="hex2-5" class="hexContainer">
        <polygon class="hex open" points="341.76914536239786,134.99999999999997 315.7883832488647,150 289.80762113533154,134.99999999999997 289.80762113533154,104.99999999999999 315.7883832488647,89.99999999999999 341.76914536239786,104.99999999999997"></polygon>
    </a>
    <a id="hex2-6" class="hexContainer">
        <polygon class="hex open" points="393.7306695894642,134.99999999999997 367.749907475931,150 341.76914536239786,134.99999999999997 341.76914536239786,104.99999999999999 367.749907475931,89.99999999999999 393.7306695894642,104.99999999999997"></polygon>
    </a>
    <a id="hex2-7" class="hexContainer">
        <polygon class="hex open" points="445.6921938165305,134.99999999999997 419.71143170299734,150 393.7306695894642,134.99999999999997 393.7306695894642,104.99999999999999 419.71143170299734,89.99999999999999 445.6921938165305,104.99999999999997"></polygon>
    </a>
    <a id="hex3-0" class="hexContainer">
        <polygon class="hex open" points="55.98076211353316,179.99999999999997 30.000000000000004,194.99999999999997 4.01923788646684,179.99999999999997 4.019237886466843,149.99999999999997 29.999999999999993,134.99999999999997 55.98076211353315,149.99999999999994"></polygon>
    </a>
    <a id="hex3-3" class="hexContainer">
        <polygon class="hex blocked" points="211.8653347947321,179.99999999999997 185.88457268119893,194.99999999999997 159.90381056766577,179.99999999999997 159.90381056766577,149.99999999999997 185.88457268119893,134.99999999999997 211.8653347947321,149.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex3-5" class="hexContainer">
        <polygon class="hex blocked" points="315.7883832488647,179.99999999999997 289.80762113533154,194.99999999999997 263.8268590217984,179.99999999999997 263.8268590217984,149.99999999999997 289.80762113533154,134.99999999999997 315.7883832488647,149.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex3-7" class="hexContainer">
        <polygon class="hex blocked" points="419.71143170299734,179.99999999999997 393.7306695894642,194.99999999999997 367.749907475931,179.99999999999997 367.749907475931,149.99999999999997 393.7306695894642,134.99999999999997 419.71143170299734,149.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex4-0" class="hexContainer">
        <polygon class="hex open" points="81.96152422706632,224.99999999999997 55.98076211353316,239.99999999999997 30,224.99999999999997 30.000000000000004,194.99999999999997 55.98076211353315,179.99999999999997 81.96152422706632,194.99999999999994"></polygon>
    </a>
    <a id="hex4-1" class="hexContainer">
        <polygon class="hex blocked" points="133.92304845413264,224.99999999999997 107.94228634059948,239.99999999999997 81.96152422706632,224.99999999999997 81.96152422706632,194.99999999999997 107.94228634059948,179.99999999999997 133.92304845413264,194.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex4-2" class="hexContainer">
        <polygon class="hex blocked" points="185.88457268119896,224.99999999999997 159.9038105676658,239.99999999999997 133.92304845413264,224.99999999999997 133.92304845413264,194.99999999999997 159.9038105676658,179.99999999999997 185.88457268119896,194.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex4-3" class="hexContainer">
        <polygon class="hex blocked" points="237.84609690826525,224.99999999999997 211.8653347947321,239.99999999999997 185.88457268119893,224.99999999999997 185.88457268119893,194.99999999999997 211.8653347947321,179.99999999999997 237.84609690826525,194.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex4-4" class="hexContainer">
        <polygon class="hex open" points="289.80762113533154,224.99999999999997 263.8268590217984,239.99999999999997 237.84609690826522,224.99999999999997 237.84609690826522,194.99999999999997 263.8268590217984,179.99999999999997 289.80762113533154,194.99999999999994"></polygon>
    </a>
    <a id="hex4-5" class="hexContainer">
        <polygon class="hex open" points="341.76914536239786,224.99999999999997 315.7883832488647,239.99999999999997 289.80762113533154,224.99999999999997 289.80762113533154,194.99999999999997 315.7883832488647,179.99999999999997 341.76914536239786,194.99999999999994"></polygon>
    </a>
    <a id="hex4-6" class="hexContainer">
        <polygon class="hex open" points="393.7306695894642,224.99999999999997 367.749907475931,239.99999999999997 341.76914536239786,224.99999999999997 341.76914536239786,194.99999999999997 367.749907475931,179.99999999999997 393.7306695894642,194.99999999999994"></polygon>
    </a>
</svg>
</div>
like image 812
VirtuosiMedia Avatar asked Oct 19 '15 11:10

VirtuosiMedia


People also ask

Which of the following CSS statement can be used to define the position of the 3D positioned element?

The perspective CSS property determines the distance between the z=0 plane and the user in order to give a 3D-positioned element some perspective.

Which of the following enable an element to have perspective as it's rotating in 3D space?

To enable true 3D perspective, you'll need to enable Children perspective on a parent element. This makes the parent element function like a “camera” that shows different angles of the child elements and creates perspective. To add Children perspective on a parent element: Select the parent element (e.g., a Section)

How do we preserve-3D transformation while nesting with other elements?

This can be fixed by setting transform-style: preserve-3d on the 3D transformed parent (the frame in our case). And then we get this nice result: However, IE10/11 only support the flat value for the transform-style property.


1 Answers

As 3d transforms can't be handled properly on svg elements, I would suggest a different approach for the grid of hexagons. It can be achieved with plain html and css as shown in this question : Responsive grid of hexagons.

This allows to make 3d transforms on child elements with the transform-style property.

Adapted to your use case, it can look like this :

DEMO

body{
  background:rgb(123, 158, 158);
  perspective:500px;
}
#categories{
  width:70%;
  margin:0 auto;
  transform:rotateX(45deg);
  transform-style: preserve-3d;
}
#categories:after{
  content:"";
  display:block;
  clear:both;
}
#categories li{
  position:relative;
  list-style-type:none;
  width:17.364%; /* = (100-4.5) / 5.5 */
  padding-bottom: 20.05%; /* =  width /0.866 */
  float:left;
  overflow:hidden;
  visibility:hidden;  
  transform: rotate(-60deg) skewY(30deg);
}

#categories li:nth-child(10n+6), #categories li:nth-child(10n+7), #categories li:nth-child(10n+8), #categories li:nth-child(10n+9), #categories li:nth-child(10n+10) {
    margin-top: -4.2%;
    margin-bottom: -4.2%;
    transform: translateX(50%) rotate(-60deg) skewY(30deg);
  }
#categories li:nth-child(10n+6){
    margin-left:0.5%;
  }
  #categories li:nth-child(5n+2) {
    margin-left:1%;
    margin-right:1%;
  }
  #categories li:nth-child(5n+3),#categories li:nth-child(5n+4){
    margin-right:1%;
  }

#categories li div{
  position:absolute;
  visibility:visible;
  width:100%; height:100%;
  text-align:center;
  color:#fff;
  overflow:hidden;  
  transform: skewY(-30deg) rotate(60deg);
  background-color:rgba(0,0,0,.2);
  transition:background-color .3s;
  border-left:2px solid #000;  
  border-right:2px solid #000;
  box-sizing:border-box;
  -webkit-backface-visibility:hidden;
}
#categories li div:hover, #categories .up:hover span:after{
  background-color:rgba(0,0,0,.5);
}
#categories li div:before, #categories li div:after{
  content:'';
  position:absolute;
  width:100%;height:49.6%;
  left:-2px;top:25.5%;
  
  border-left:2px solid #000;
  border-right:2px solid #000;
  transform:rotate(60deg);
  visibility:visible;
}
#categories li div:before{
    transform:rotate(-60deg);
}

#categories li img{
  display:block;
  left:-100%; right:-100%;
  width: auto; height:100%;
  margin:0 auto;
  visibility:visible;
}
#categories .up, #categories .up div{
  transform-style:preserve-3d;
  overflow:visible;
  visibility:hidden;
  background-color:transparent;
}
#categories .up span{
  display:block;
  width:100%;height:100%;
  position:absolute;
  top:0; left:0;
  overflow:hidden;
}
#categories .up span:after{
  content:'';
  position:absolute;
  left:0;top:0;
  width:100%;height:100%;
  border-left:2px solid #000;
  border-right:2px solid #000;
  box-sizing:border-box;
  background-color:rgba(0,0,0,.2);
  transform: skewY(-30deg) rotate(60deg);
  transition:background-color .3s;
  visibility:visible;
}

#categories .up img{
  width:100%; height:auto;
  position:absolute;
  transform-origin: 50% 100%;
  transform: rotateX(-45deg);
  z-index:1;
}
<ul id="categories" class="clr">
	  <li><div></div></li>
  <li class="up"><span></span><div><img src="https://farm9.staticflickr.com/8461/8048823381_0fbc2d8efb.jpg" alt=""/></div></li>
  <li><div></div></li>  
  <li><div></div></li>
  <li class="up"><span></span><div><img src="https://farm7.staticflickr.com/6217/6216951796_e50778255c.jpg" alt=""/></div></li>
  <li class="pusher"></li>
  <li class="pusher"></li>
  <li class="pusher"></li>
  <li><div></div></li>
  <li class="pusher"></li>
  <li><div></div></li>
  <li><div></div></li>
  <li><div></div></li>
  <li class="pusher"></li>
  <li><div></div></li>
  <li class="up"><span></span><div><img src="https://farm5.staticflickr.com/4144/5053682635_b348b24698.jpg" alt=""/></div></li>
  <li class="pusher"></li>
  <li><div></div></li>
  <li><div></div></li>
</ul>

This grid of hexagons can be adapted to several use cases (number of hexagons per row, hexagon alignment...) more examples in this collection : Responsive grids of hexagons

like image 50
web-tiki Avatar answered Nov 15 '22 22:11

web-tiki