16 CSS Image Gallery Designs 13 / 16

CSS 3D Cube Image Viewer

A CSS 3D cube with six faces each showing an iconic world bridge illustration — buttons rotate the cube to any face via JS-applied transforms.

CSS + JS MIT licensed
Live Demo Open in tab
Open in playground

The code

<div class="ig-13">
  <div class="ig-13__viewport">
    <div class="ig-13__cube" id="ig-13-cube">

      <!-- Front: Golden Gate Bridge -->
      <div class="ig-13__face ig-13__face--front">
        <svg viewBox="0 0 260 260" xmlns="http://www.w3.org/2000/svg">
          <defs><linearGradient id="ggg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#4488cc"/><stop offset="50%" stop-color="#88aacc"/><stop offset="100%" stop-color="#2a5a7a"/></linearGradient><filter id="ggf"><feGaussianBlur stdDeviation="4"/></filter></defs>
          <rect width="260" height="260" fill="url(#ggg)"/>
          <g filter="url(#ggf)" opacity=".4"><ellipse cx="130" cy="90" rx="100" ry="30" fill="#c8d8e8"/></g>
          <!-- Bay -->
          <path d="M0,185 Q65,172 130,180 Q195,172 260,182 L260,260 L0,260 Z" fill="#1a4a6a"/>
          <!-- Bridge towers -->
          <g fill="#cc3010">
            <rect x="70" y="80" width="14" height="110"/><rect x="176" y="80" width="14" height="110"/>
            <!-- Tower details -->
            <rect x="66" y="80" width="22" height="10"/><rect x="172" y="80" width="22" height="10"/>
            <rect x="66" y="100" width="22" height="8"/><rect x="172" y="100" width="22" height="8"/>
            <rect x="66" y="120" width="22" height="8"/><rect x="172" y="120" width="22" height="8"/>
            <!-- Tops -->
            <rect x="74" y="72" width="6" height="12"/><rect x="180" y="72" width="6" height="12"/>
          </g>
          <!-- Main cables -->
          <g stroke="#cc3010" stroke-width="4" fill="none">
            <path d="M0,145 Q77,105 130,130 Q183,105 260,130"/>
            <path d="M0,150 Q77,110 130,135 Q183,110 260,135"/>
          </g>
          <!-- Hanger cables -->
          <g stroke="#cc3010" stroke-width="1" fill="none" opacity=".7">
            <line x1="20" y1="148" x2="20" y2="178"/><line x1="40" y1="138" x2="40" y2="178"/>
            <line x1="60" y1="132" x2="60" y2="178"/><line x1="100" y1="125" x2="100" y2="178"/>
            <line x1="120" y1="125" x2="120" y2="178"/><line x1="140" y1="125" x2="140" y2="178"/>
            <line x1="160" y1="126" x2="160" y2="178"/><line x1="200" y1="130" x2="200" y2="178"/>
            <line x1="220" y1="136" x2="220" y2="178"/><line x1="240" y1="142" x2="240" y2="178"/>
          </g>
          <!-- Deck -->
          <rect x="0" y="178" width="260" height="8" fill="#aa2808"/>
          <!-- Hills bg -->
          <g fill="#1a3a1a" opacity=".5"><polygon points="0,185 0,160 45,140 90,160 90,185"/><polygon points="170,185 170,158 215,138 260,158 260,185"/></g>
          <!-- Fog wisps -->
          <g opacity=".3" fill="#c8d8e8" filter="url(#ggf)"><ellipse cx="40" cy="160" rx="50" ry="18"/><ellipse cx="215" cy="155" rx="45" ry="16"/></g>
        </svg>
      </div>

      <!-- Right: Sydney Harbour Bridge -->
      <div class="ig-13__face ig-13__face--right">
        <svg viewBox="0 0 260 260" xmlns="http://www.w3.org/2000/svg">
          <defs><linearGradient id="shg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#1a3a5c"/><stop offset="50%" stop-color="#2a5a80"/><stop offset="100%" stop-color="#1a3050"/></linearGradient></defs>
          <rect width="260" height="260" fill="url(#shg)"/>
          <!-- Harbour water -->
          <path d="M0,190 Q65,178 130,185 Q195,178 260,188 L260,260 L0,260 Z" fill="#1a3a5a"/>
          <!-- Sydney Opera House in bg -->
          <g fill="#d8d0c8" opacity=".7">
            <path d="M10,190 Q30,160 50,185 Z"/><path d="M22,190 Q45,155 68,185 Z"/>
            <path d="M55,190 Q72,165 90,185 Z"/>
          </g>
          <!-- Bridge arch -->
          <path d="M30,195 Q130,40 230,195" stroke="#555566" stroke-width="22" fill="none"/>
          <path d="M30,195 Q130,45 230,195" stroke="#888898" stroke-width="8" fill="none"/>
          <!-- Pylons -->
          <g fill="#3a3a4a"><rect x="22" y="160" width="18" height="40"/><rect x="220" y="160" width="18" height="40"/><rect x="18" y="157" width="26" height="10" rx="2"/><rect x="216" y="157" width="26" height="10" rx="2"/></g>
          <!-- Hanger rods -->
          <g stroke="#555566" stroke-width="1.5" fill="none">
            <line x1="50" y1="152" x2="50" y2="190"/><line x1="70" y1="120" x2="70" y2="190"/>
            <line x1="90" y1="100" x2="90" y2="190"/><line x1="110" y1="88" x2="110" y2="190"/>
            <line x1="130" y1="82" x2="130" y2="190"/><line x1="150" y1="88" x2="150" y2="190"/>
            <line x1="170" y1="100" x2="170" y2="190"/><line x1="190" y1="120" x2="190" y2="190"/>
            <line x1="210" y1="152" x2="210" y2="190"/>
          </g>
          <!-- Bridge deck -->
          <rect x="25" y="185" width="210" height="10" fill="#4a4a5a"/>
          <!-- City skyline -->
          <g fill="#1a2a3a"><rect x="120" y="155" width="25" height="35"/><rect x="148" y="148" width="20" height="42"/><rect x="170" y="158" width="18" height="32"/><rect x="190" y="152" width="22" height="38"/><rect x="215" y="160" width="15" height="30"/></g>
          <!-- Stars -->
          <g fill="#fff" opacity=".6"><circle cx="25" cy="20" r="1"/><circle cx="70" cy="8" r="1.1"/><circle cx="120" cy="15" r=".9"/><circle cx="185" cy="8" r="1"/><circle cx="235" cy="20" r=".9"/></g>
          <!-- Fireworks glow -->
          <circle cx="130" cy="55" r="30" fill="#ff4020" opacity=".08"/>
        </svg>
      </div>

      <!-- Back: Tower Bridge -->
      <div class="ig-13__face ig-13__face--back">
        <svg viewBox="0 0 260 260" xmlns="http://www.w3.org/2000/svg">
          <defs><linearGradient id="tbg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#c8d8e8"/><stop offset="40%" stop-color="#a0b8cc"/><stop offset="100%" stop-color="#3a5a6a"/></linearGradient><filter id="tbf"><feGaussianBlur stdDeviation="4"/></filter></defs>
          <rect width="260" height="260" fill="url(#tbg)"/>
          <!-- Overcast fog -->
          <g filter="url(#tbf)" opacity=".5"><ellipse cx="80" cy="50" rx="80" ry="30" fill="#d0dce8"/><ellipse cx="190" cy="40" rx="70" ry="25" fill="#c8d8e8"/></g>
          <!-- Thames river -->
          <path d="M0,195 Q65,183 130,190 Q195,183 260,192 L260,260 L0,260 Z" fill="#3a5a70"/>
          <!-- Victorian towers -->
          <g fill="#5a4a30">
            <!-- Left tower -->
            <rect x="60" y="120" width="34" height="80"/>
            <rect x="55" y="118" width="44" height="12"/>
            <!-- Tower turrets -->
            <rect x="58" y="90" width="10" height="32"/><rect x="76" y="90" width="10" height="32"/>
            <polygon points="55,90 63,72 71,90"/><polygon points="73,90 81,72 89,90"/>
            <!-- Windows -->
            <g fill="#6888aa" opacity=".7"><rect x="63" y="128" width="8" height="12" rx="2"/><rect x="75" y="128" width="8" height="12" rx="2"/><rect x="63" y="148" width="8" height="12" rx="2"/><rect x="75" y="148" width="8" height="12" rx="2"/></g>
          </g>
          <g fill="#5a4a30">
            <!-- Right tower -->
            <rect x="166" y="120" width="34" height="80"/>
            <rect x="161" y="118" width="44" height="12"/>
            <rect x="164" y="90" width="10" height="32"/><rect x="182" y="90" width="10" height="32"/>
            <polygon points="161,90 169,72 177,90"/><polygon points="179,90 187,72 195,90"/>
            <g fill="#6888aa" opacity=".7"><rect x="169" y="128" width="8" height="12" rx="2"/><rect x="181" y="128" width="8" height="12" rx="2"/><rect x="169" y="148" width="8" height="12" rx="2"/><rect x="181" y="148" width="8" height="12" rx="2"/></g>
          </g>
          <!-- High walkway -->
          <rect x="70" y="108" width="120" height="8" fill="#6a5a40"/>
          <!-- Bridge deck with bascules -->
          <rect x="0" y="185" width="60" height="10" fill="#5a4a30"/>
          <rect x="200" y="185" width="60" height="10" fill="#5a4a30"/>
          <!-- Open bascules (raised) -->
          <path d="M60,190 Q72,170 80,140 L94,195" fill="#6a5a40" opacity=".9"/>
          <path d="M200,190 Q188,170 180,140 L166,195" fill="#6a5a40" opacity=".9"/>
          <!-- Suspension cables -->
          <g stroke="#6a5a40" stroke-width="3" fill="none"><path d="M0,178 Q65,165 94,185"/><path d="M260,178 Q195,165 166,185"/></g>
          <!-- City / St Paul's in background -->
          <g fill="#4a4838" opacity=".4"><rect x="100" y="150" width="60" height="45"/><polygon points="95,150 130,130 165,150"/><circle cx="130" cy="130" r="12" fill="none" stroke="#4a4838" stroke-width="3" opacity=".4"/></g>
          <!-- River reflections -->
          <g stroke="#6a8898" stroke-width="1" fill="none" opacity=".4"><path d="M0,205 Q65,198 130,203 Q195,198 260,202"/></g>
        </svg>
      </div>

      <!-- Left: Millau Viaduct -->
      <div class="ig-13__face ig-13__face--left">
        <svg viewBox="0 0 260 260" xmlns="http://www.w3.org/2000/svg">
          <defs><linearGradient id="mvg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#8ab0c8"/><stop offset="40%" stop-color="#b0c8d8"/><stop offset="100%" stop-color="#d0e0e8"/></linearGradient></defs>
          <rect width="260" height="260" fill="url(#mvg)"/>
          <!-- Valley mist -->
          <g opacity=".4"><ellipse cx="130" cy="215" rx="200" ry="55" fill="#d8e8f0"/></g>
          <!-- Mountain cliffs each side -->
          <polygon points="0,260 0,140 55,100 80,160 80,260" fill="#6a7a6a"/>
          <polygon points="260,260 260,135 205,95 180,155 180,260" fill="#6a7a6a"/>
          <!-- Valley -->
          <path d="M75,230 Q130,215 185,230 L185,260 L75,260 Z" fill="#3a5a3a" opacity=".5"/>
          <!-- Mast towers -->
          <g fill="#bbbbc0">
            <!-- 7 masts -->
            <rect x="30" y="130" width="6" height="80"/><line x1="33" y1="100" x2="33" y2="135" stroke="#bbbbc0" stroke-width="6"/>
            <rect x="65" y="118" width="6" height="82"/><line x1="68" y1="88" x2="68" y2="122" stroke="#bbbbc0" stroke-width="6"/>
            <rect x="100" y="108" width="6" height="82"/><line x1="103" y1="78" x2="103" y2="112" stroke="#bbbbc0" stroke-width="6"/>
            <rect x="127" y="105" width="6" height="80"/><line x1="130" y1="75" x2="130" y2="109" stroke="#bbbbc0" stroke-width="6"/>
            <rect x="154" y="108" width="6" height="82"/><line x1="157" y1="78" x2="157" y2="112" stroke="#bbbbc0" stroke-width="6"/>
            <rect x="189" y="118" width="6" height="82"/><line x1="192" y1="88" x2="192" y2="122" stroke="#bbbbc0" stroke-width="6"/>
            <rect x="224" y="130" width="6" height="80"/><line x1="227" y1="100" x2="227" y2="135" stroke="#bbbbc0" stroke-width="6"/>
          </g>
          <!-- Stay cables from mast tops -->
          <g stroke="#aaaaaf" stroke-width="1" fill="none" opacity=".7">
            <path d="M33,100 Q50,155 65,160"/><path d="M33,100 Q18,155 10,165"/>
            <path d="M68,88 Q84,148 100,158"/><path d="M68,88 Q52,148 40,158"/>
            <path d="M130,75 Q115,148 100,160"/><path d="M130,75 Q145,148 160,160"/>
            <path d="M192,88 Q176,148 160,158"/><path d="M192,88 Q208,148 220,158"/>
            <path d="M227,100 Q210,155 195,160"/><path d="M227,100 Q242,155 250,165"/>
          </g>
          <!-- Deck -->
          <rect x="8" y="160" width="244" height="8" fill="#b0b8be"/>
          <!-- Pier legs taper down into mist -->
          <g stroke="#bbbbc0" stroke-width="8" fill="none" opacity=".6">
            <line x1="33" y1="167" x2="33" y2="230"/><line x1="68" y1="167" x2="68" y2="225"/>
            <line x1="103" y1="167" x2="103" y2="220"/><line x1="130" y1="167" x2="130" y2="218"/>
            <line x1="157" y1="167" x2="157" y2="220"/><line x1="192" y1="167" x2="192" y2="225"/>
            <line x1="227" y1="167" x2="227" y2="230"/>
          </g>
          <!-- Clouds in valley -->
          <g fill="#e8f0f8" opacity=".5"><ellipse cx="80" cy="218" rx="55" ry="22"/><ellipse cx="180" cy="215" rx="50" ry="20"/></g>
        </svg>
      </div>

      <!-- Top: Rialto Bridge -->
      <div class="ig-13__face ig-13__face--top">
        <svg viewBox="0 0 260 260" xmlns="http://www.w3.org/2000/svg">
          <defs><linearGradient id="rbg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#6aaad4"/><stop offset="50%" stop-color="#88c4e8"/><stop offset="100%" stop-color="#4488b0"/></linearGradient></defs>
          <rect width="260" height="260" fill="url(#rbg)"/>
          <!-- Venetian canal -->
          <!-- Buildings flanking canal -->
          <g fill="#c8a870"><rect x="0" y="60" width="65" height="200"/><rect x="195" y="55" width="65" height="205"/></g>
          <g fill="#b89858"><rect x="0" y="60" width="65" height="12"/><rect x="195" y="55" width="65" height="12"/></g>
          <!-- Windows -->
          <g fill="#6888aa" opacity=".7"><rect x="8" y="75" width="10" height="14" rx="2"/><rect x="24" y="75" width="10" height="14" rx="2"/><rect x="40" y="75" width="10" height="14" rx="2"/><rect x="8" y="100" width="10" height="14" rx="2"/><rect x="24" y="100" width="10" height="14" rx="2"/><rect x="205" y="70" width="10" height="14" rx="2"/><rect x="220" y="70" width="10" height="14" rx="2"/><rect x="238" y="70" width="10" height="14" rx="2"/></g>
          <!-- Canal water -->
          <rect x="65" y="0" width="130" height="260" fill="#4488aa"/>
          <!-- Canal reflections -->
          <g stroke="#5599bb" stroke-width="1" fill="none" opacity=".4"><path d="M65,80 Q130,72 195,80"/><path d="M65,110 Q130,103 195,110"/><path d="M65,140 Q130,133 195,140"/><path d="M65,170 Q130,163 195,170"/></g>
          <!-- Rialto bridge arch -->
          <g fill="#d4b080">
            <path d="M65,140 Q95,90 130,75 Q165,90 195,140 L195,155 Q165,105 130,90 Q95,105 65,155 Z"/>
            <rect x="65" y="155" width="130" height="12"/>
          </g>
          <!-- Bridge arcade shops -->
          <g fill="#8a6030">
            <rect x="80" y="100" width="12" height="35" rx="2"/><rect x="96" y="95" width="12" height="40" rx="2"/>
            <rect x="112" y="92" width="12" height="42" rx="2"/><rect x="128" y="91" width="12" height="42" rx="2"/>
            <rect x="144" y="92" width="12" height="40" rx="2"/><rect x="160" y="95" width="12" height="38" rx="2"/>
          </g>
          <!-- Center arch opening -->
          <path d="M107,100 Q130,80 153,100 L153,145 L107,145 Z" fill="#4488aa" opacity=".8"/>
          <!-- Gondola beneath -->
          <g transform="translate(130,210)">
            <path d="M-20,0 Q-15,-5 0,-4 Q15,-5 22,0 Q18,6 -18,6 Z" fill="#0a0a0a"/>
            <rect x="-2" y="-12" width="3" height="12" fill="#6a4020"/>
          </g>
        </svg>
      </div>

      <!-- Bottom: Brooklyn Bridge -->
      <div class="ig-13__face ig-13__face--bottom">
        <svg viewBox="0 0 260 260" xmlns="http://www.w3.org/2000/svg">
          <defs><linearGradient id="bbg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#1a2a4a"/><stop offset="50%" stop-color="#2a4060"/><stop offset="100%" stop-color="#1a2a3a"/></linearGradient></defs>
          <rect width="260" height="260" fill="url(#bbg)"/>
          <!-- City lights distant -->
          <g fill="#ffd060" opacity=".6"><rect x="5" y="185" width="4" height="6"/><rect x="14" y="180" width="4" height="8"/><rect x="22" y="183" width="4" height="5"/><rect x="220" y="180" width="4" height="8"/><rect x="230" y="184" width="4" height="6"/><rect x="240" y="178" width="4" height="10"/><rect x="250" y="182" width="4" height="7"/></g>
          <!-- East River -->
          <path d="M0,195 Q65,183 130,190 Q195,183 260,192 L260,260 L0,260 Z" fill="#141e30"/>
          <g stroke="#1e3040" stroke-width="1.5" fill="none" opacity=".5"><path d="M0,210 Q65,202 130,207 Q195,202 260,206"/></g>
          <!-- Gothic towers -->
          <g fill="#8a7050">
            <!-- Left tower -->
            <rect x="72" y="100" width="36" height="100"/>
            <rect x="69" y="98" width="42" height="12"/>
            <!-- Gothic arches at top -->
            <path d="M72,98 Q90,78 108,98" fill="#7a6040"/>
            <path d="M75,98 Q90,81 105,98" fill="none" stroke="#6a5030" stroke-width="2"/>
            <!-- Windows -->
            <g fill="#3a5070" opacity=".8"><path d="M78,110 Q85,100 92,110 L92,128 L78,128 Z"/><path d="M96,112 Q103,102 110,112 L110,128 L96,128 Z"/></g>
            <!-- Right tower -->
            <rect x="152" y="100" width="36" height="100"/>
            <rect x="149" y="98" width="42" height="12"/>
            <path d="M152,98 Q170,78 188,98" fill="#7a6040"/>
            <path d="M155,98 Q170,81 185,98" fill="none" stroke="#6a5030" stroke-width="2"/>
            <g fill="#3a5070" opacity=".8"><path d="M158,110 Q165,100 172,110 L172,128 L158,128 Z"/><path d="M176,112 Q183,102 190,112 L190,128 L176,128 Z"/></g>
          </g>
          <!-- Main cables -->
          <g stroke="#8a7050" stroke-width="5" fill="none"><path d="M0,158 Q90,118 130,140 Q170,118 260,145"/></g>
          <!-- Suspender cables fan -->
          <g stroke="#6a5840" stroke-width="1.2" fill="none" opacity=".7">
            <line x1="90" y1="118" x2="40" y2="190"/><line x1="90" y1="118" x2="58" y2="190"/><line x1="90" y1="118" x2="76" y2="190"/><line x1="90" y1="118" x2="95" y2="190"/>
            <line x1="170" y1="118" x2="165" y2="190"/><line x1="170" y1="118" x2="184" y2="190"/><line x1="170" y1="118" x2="202" y2="190"/><line x1="170" y1="118" x2="220" y2="190"/>
            <line x1="130" y1="128" x2="112" y2="190"/><line x1="130" y1="128" x2="130" y2="190"/><line x1="130" y1="128" x2="148" y2="190"/>
          </g>
          <!-- Road deck -->
          <rect x="0" y="190" width="260" height="8" fill="#5a5040"/>
          <!-- Stars -->
          <g fill="#fff" opacity=".6"><circle cx="20" cy="25" r="1"/><circle cx="60" cy="15" r="1.1"/><circle cx="105" cy="28" r=".9"/><circle cx="165" cy="18" r="1"/><circle cx="215" cy="25" r=".9"/><circle cx="248" cy="12" r="1.1"/></g>
          <!-- Water taxi -->
          <g transform="translate(60,222)">
            <rect x="-18" y="-5" width="36" height="10" rx="4" fill="#cc2020"/>
            <rect x="-8" y="-12" width="18" height="8" rx="2" fill="#aa1818"/>
          </g>
        </svg>
      </div>

    </div>
  </div>

  <div class="ig-13__controls" id="ig-13-controls">
    <button class="ig-13__btn ig-13--active" data-y="0" data-x="-10">Front</button>
    <button class="ig-13__btn" data-y="90" data-x="-10">Right</button>
    <button class="ig-13__btn" data-y="180" data-x="-10">Back</button>
    <button class="ig-13__btn" data-y="-90" data-x="-10">Left</button>
    <button class="ig-13__btn" data-y="0" data-x="-90">Top</button>
    <button class="ig-13__btn" data-y="0" data-x="90">Bottom</button>
  </div>
  <p class="ig-13__label">6 iconic bridges of the world</p>
</div>
<script>
(function(){
  const cube=document.getElementById('ig-13-cube');
  const btns=document.querySelectorAll('#ig-13-controls .ig-13__btn');
  if(!cube)return;
  btns.forEach(btn=>{
    btn.addEventListener('click',()=>{
      btns.forEach(b=>b.classList.remove('ig-13--active'));
      btn.classList.add('ig-13--active');
      const y=Number(btn.dataset.y)||0;
      const x=Number(btn.dataset.x)||-10;
      cube.style.transform=`rotateX(${x}deg) rotateY(${y}deg)`;
    });
  });
}());
</script>
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
body{background:#0a0c10;font-family:'DM Sans',sans-serif;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;gap:2rem;padding:2rem}
.ig-13{display:flex;flex-direction:column;align-items:center;gap:1.8rem}
.ig-13__viewport{perspective:900px;width:260px;height:260px}
.ig-13__cube{width:100%;height:100%;position:relative;transform-style:preserve-3d;transform:rotateX(-10deg) rotateY(0deg);transition:transform .65s cubic-bezier(.25,.46,.45,.94)}
.ig-13__face{position:absolute;width:100%;height:100%;backface-visibility:hidden;border-radius:8px;overflow:hidden;border:2px solid rgba(255,255,255,.12)}
.ig-13__face svg{width:100%;height:100%;display:block}
.ig-13__face--front {transform:translateZ(130px)}
.ig-13__face--back  {transform:rotateY(180deg) translateZ(130px)}
.ig-13__face--right {transform:rotateY(90deg)  translateZ(130px)}
.ig-13__face--left  {transform:rotateY(-90deg) translateZ(130px)}
.ig-13__face--top   {transform:rotateX(90deg)  translateZ(130px)}
.ig-13__face--bottom{transform:rotateX(-90deg) translateZ(130px)}
.ig-13__controls{display:flex;gap:.6rem;flex-wrap:wrap;justify-content:center}
.ig-13__btn{background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.15);color:rgba(255,255,255,.75);font-size:.72rem;font-weight:600;letter-spacing:.08em;padding:.4rem .9rem;border-radius:8px;cursor:pointer;font-family:'DM Sans',sans-serif;transition:background .2s ease,color .2s ease;text-transform:uppercase}
.ig-13__btn:hover{background:rgba(255,255,255,.18);color:#fff}
.ig-13__btn.ig-13--active{background:rgba(255,255,255,.22);color:#fff;border-color:rgba(255,255,255,.4)}
.ig-13__label{color:rgba(255,255,255,.35);font-size:.7rem;letter-spacing:.08em;text-transform:uppercase}
@media(prefers-reduced-motion:reduce){.ig-13__cube{transition:none}}
(function(){
  const cube=document.getElementById('ig-13-cube');
  const btns=document.querySelectorAll('#ig-13-controls .ig-13__btn');
  if(!cube)return;
  btns.forEach(btn=>{
    btn.addEventListener('click',()=>{
      btns.forEach(b=>b.classList.remove('ig-13--active'));
      btn.classList.add('ig-13--active');
      const y=Number(btn.dataset.y)||0;
      const x=Number(btn.dataset.x)||-10;
      cube.style.transform=`rotateX(${x}deg) rotateY(${y}deg)`;
    });
  });
}());

How this works

The cube is a div with transform-style: preserve-3d inside a perspective: 900px viewport. The six face elements each receive a different translateZ and rotateX/Y to place them on the correct side of a cube: front uses translateZ(130px), back rotateY(180deg) translateZ(130px), and the four sides use 90-degree rotations. The translateZ value (130px) equals half the cube edge length (260px).

JavaScript maps each button's data-x and data-y attributes to a rotateX / rotateY transform applied to the cube container. Because the cube rotates as a whole unit, the faces follow automatically. A CSS transition: transform .65s cubic-bezier animates the rotation smoothly between any two states.

Customize

  • Change cube size by editing the face position: absolute; width/height: 100% and the translateZ(130px) value — the Z offset must always equal half the cube edge length.
  • Add an auto-rotation idle animation by applying a CSS @keyframes rotation to the cube and pausing it via animation-play-state on user interaction.
  • Change the transition easing from cubic-bezier(.25,.46,.45,.94) to cubic-bezier(.34,1.56,.64,1) for a spring overshoot on face changes.
  • Add face labels as position: absolute overlays on each face using z-index to appear above the SVG content.
  • Change the viewport perspective from 900px to 600px for a wider-angle 3D look, or 1400px for a flatter near-isometric appearance.

Watch out for

  • The cube translateZ value must exactly equal half the edge length — if the cube is 260px wide but translateZ is 120px, the faces will overlap or gap.
  • backface-visibility: hidden on each face prevents back faces from showing through — without it, the back face appears mirrored over the front when rotating.
  • CSS 3D transforms require transform-style: preserve-3d on every intermediate ancestor between the perspective parent and the 3D elements; any ancestor with overflow: hidden will flatten the 3D context.

Browser support

ChromeSafariFirefoxEdge
36+ 9+ 16+ 36+

CSS 3D transforms with preserve-3d broadly supported; -webkit- prefix needed for older Safari.

Search CodeFronts

Loading…