Pure CSS Scenes & objects #hover

Door in pure CSS

Hover or focus to open. The light behind is just the frame’s background.

  • 35 lines of CSS
  • 3 lines of HTML
  • No JavaScript
  • No dependencies
  • MIT licensed
GitHub

How it works

  1. The frame holds the perspective; the leaf rotates with transform-origin: left (the hinges).
  2. perspective-origin: 120% 50% moves the camera to the right of the frame, so the open door does not collapse into a thin line.
  3. The "light" is simply the frame’s background, revealed as the leaf swings away.
  4. tabindex="0" plus :focus makes it work by tap and by keyboard.

Key techniques

  • transform-origin: left
  • transition on :hover / :focus
  • perspective-origin

Copy-paste code

HTML 3 lines

<div class="door" tabindex="0">
  <div class="leaf"><i></i></div>
</div>

CSS 35 lines

.door {
  position: relative;
  width: 150px;
  height: 250px;
  border: 8px solid #3a2a1c;
  border-bottom: 0;
  background: radial-gradient(ellipse at 50% 70%, #fff6c9, #ffb547 55%, #7a4a12);
  perspective: 700px;
  perspective-origin: 120% 50%;
  cursor: pointer;
}

.leaf {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, #8a5a33, #6d4424);
  transform-origin: left center;
  transition: transform 0.9s cubic-bezier(0.3, 1.2, 0.5, 1);
}

.door:hover .leaf,
.door:focus .leaf {
  transform: rotateY(-105deg);
}

/* knob */
.leaf i {
  position: absolute;
  top: 50%;
  right: 12px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #ffd36b;
}

Sass source 39 lines

.d-door {
  position: relative;
  width: 110px;
  height: 180px;
  border: 6px solid #3a2a1c;
  border-bottom: 0;
  background: radial-gradient(ellipse at 50% 70%, #fff6c9, #ffb547 55%, #7a4a12);
  perspective: 600px;
  perspective-origin: 120% 50%;
  cursor: pointer;
  outline-offset: 6px;

  &__leaf {
    position: absolute;
    inset: 0;
    background:
      linear-gradient(#0003, #0003) 14px 14px / calc(100% - 28px) 62px no-repeat,
      linear-gradient(#0003, #0003) 14px 90px / calc(100% - 28px) 70px no-repeat,
      linear-gradient(90deg, #8a5a33, #6d4424);
    transform-origin: left center;
    transition: transform 0.9s cubic-bezier(0.3, 1.2, 0.5, 1);

    // knob
    i {
      position: absolute;
      top: 50%;
      right: 9px;
      width: 10px;
      height: 10px;
      border-radius: 50%;
      background: #ffd36b;
    }
  }

  &:hover &__leaf,
  &:focus &__leaf {
    transform: rotateY(-105deg);
  }
}
Standalone snippet · plain CSS, no build step, no dependencies.