Building a macOS Window with CSS

With just a few lines of HTML and CSS you can do amazing things. Lately I wanted to frame images in macOS styled window frames. To reduce the load and keep everything small i’ve decided to build it from HTML and CSS rather than using a background image, wrapped around the actual image.
Take a look at the finished page.

There is a Gist with the code needed, feel free to use it.

Screenshot of a Mac OSX Window

The window is essentially made out of 3 divs. One for the whole frame, one for the bar and one for the content. The content div can be replaced with whatever should be in the window eg. an image or an iframe.

<div class="window">
  <div class="window__bar">Title</div>
  <div class="window__content"></div>

By using the :before pseudo class it’s also possible to build it the whole thing with only div. You can find an example at the end of this post.

Now the window is ready to be styled. Here is the CSS for the frame:

.window {
  border-top-left-radius: 6px;
  border-top-right-radius: 6px;
  border: 1px solid #adadad;
  max-width: 500px;
  margin: 0 auto;
  box-shadow: 0 20px 70px rgba(0, 0, 0, 0.55);

The frame is quite easy. It’s just a box with a big box shadow which is pushed down a little. I picked the colors and dimensions with photoshop and the box shadow by eye.

Now to the interesting part. The top bar. To avoid more HTML I’ve decided to build the buttons in the top bar with pure CSS. This prevents a user from hovering the buttons, but it’s enough for the decorative purpose of the thing.

To build the buttons I’m using a radial gradient, which looks like this:

background: radial-gradient(
	7px at 14px 50%,
	#ff5e57 0px,
	#ff635a 5px,
	#fd5249 6px,
	rgba(255, 255, 255, 0) 7px

This sizes and positions the gradient 13px at 14px 50%, draws the stops of the button gradient 0px, 5px, 6px and sets the last color to a transparent white rgba(255, 255, 255, 0) 7px to avoid that the whole top bar gets colored in the color of the button.

To complete the top bar 3 radial gradients needs to be combined with a linear gradient. The css background property allows the use of multiple backgrounds which are stacked on top of each other, whereas the first one is the top most and the last the bottom most.

This results in following code:

.window__bar {
  radial-gradient(7px at 14px 50%, #ff5e57 0px, #ff635a 5px, #fd5249 6px, rgba(255, 255, 255, 0) 7px),
  radial-gradient(7px at 34px 50%, #ffbd2e 0px, #ffc42f 5px, #fcb91b 6px, rgba(255, 255, 255, 0) 7px),
  radial-gradient(7px at 54px 50%, #cfcfcf 0px, #d3d3d3 5px, #c6c6c6 6px, rgba(255, 255, 255, 0) 7px),
  linear-gradient(to top, #cccccc 0%, #d6d6d6 1px, #ebebeb 100%);

Which results in this: The Top Bar made from css

The rest of the code for the top bar is shown below. It aligns the title and defines height and border-radius of the bar.

.window__bar {
  border: 1px solid white;
  border-left-color: #f3f3f3;
  border-right-color: #f3f3f3;
  border-bottom-color: #bdbdbd;
  border-top-left-radius: 6px;
  border-top-right-radius: 6px;
  height: 20px;
  text-align: center;
  color: #505151;
  font-size: 12px;
  font-weight: bold;
  line-height: 20px;
  vertical-align: middle;

Last but not least there is the content area, which isn’t very special and can either be an div or anything other. In this example i decided to make it an autosizing div.

  .window__content {
    &:before {
      display: block;
      padding-top: 100%;

The final result

The one div solution