Thinking Outside the Box

Author picture
Tom Phippen
Posted by
Tom Phippen
Date:

One of our recent re-design and re-theme projects for a client's existing Drupal 7 website involved creating a responsive Drupal theme in which our designer took typical mobile-responsive text plus image layouts and embellished them with detailed design features to enhance the presentation and to tie the styles of the site in more closely with an accompanying printed brochure that we also designed.

The coupled text and image side-by-side feature promoted the brochure and used elements that were designed to be supported by CSS delivery alone. As the design work was being produced and shared within the team, we took the time to explore how we might deliver the features and ensure that we weren't proposing something that would cause issues at the theming stage. But as a themer, it's great to have challenges like this where we know taking that extra bit of effort to implement an idea can make a big difference to the finished product.

Since it's a good example of this collaborative design and theming process, I thought I'd share the method used to deliver the code in the hope it helps or inspires others to explore the CSS techniques that are becoming available to us through improving browser support.

The design for the content feature:

The desktop visual for the design looked just like this:

Brochure mockup

With the image and text being able to switch sides as needed.

The HTML

There were a few easy ways to get this to work, the most obvious one being saving the red box as part of the image. But we wanted it to be easy for the client to update – just requiring them to upload a suitably sized image, so they don't have anything blocking them adding content. We also wanted to do it via HTML & CSS as it give us more flexibility responsively, and would make it easier if the design changes in the future.

The HTML was kept simple, only one wrapping <div> is needed as the CSS is using pseudo elements.

<div class="boxed-image__wrapper">
  <img src="filename.jpg" class="boxed-image__img">
</div>

The CSS

The Box

The first question was is it possible to achieve the effect of the an image going through a box. After trying to think of a clever way to do it, looking up what cutting edge CSS goodies have enough browser support to try. Having come up with nothing the obvious answer was to cheat!

Rather than trying to get the image going through anything, it just needs to go between 2 half boxes, by adding a bordered box to both the :before and :after elements we can z-index them differently and get the desired effect. The bottom and top layers are coloured red and blue to demonstrate.

View Demo 1

The CSS for this is quite simple

.boxed-image__wrapper {
  position: relative;
  padding: 30px 0;
  width: 100%;
}
.boxed-image__img {
  width: 100%;
  height: auto;
  display: block;
  position: relative;
  z-index: 6;
}
.boxed-image__wrapper:before, 
.boxed-image__wrapper:after
{
  content: "";
  display: block;
  width: 250px;
  height: auto;
  position: absolute;
  top:    20px;
  bottom: 20px;
  left: 50%;
  margin-left: -125px;
  z-index: 4;
  border: 10px solid red;
}
.boxed-image__wrapper:after {
  border-color: transparent;
  border-right-color: blue;
  z-index: 8;
}

The Angle

The next step is getting the angle on the image. A 3D perspective transform along with a rotation seems like it does the job. But it moves the image slightly in from the side of the viewport, and has noticeably more jank it's not quite suitable.

View Demo 2

.boxed-image__img {
  transform: perspective(2000px) rotateY(20deg);
}

The fallback option was clipping paths, the major downside of this is that they do what they say and clip the image. But are overall more reliable.

View Demo 3

.boxed-image__img {
  -webkit-clip-path: polygon(0 0, 100% 10%, 100% 90%, 0% 100%);
          clip-path: polygon(0 0, 100% 10%, 100% 90%, 0% 100%);
}

Responsiveness

The red box is overwhelming on small screens so we have it kick in when the viewport is 32em wide, we also have the box widen when the viewport is 60em wide, from 250px to 400px.

View Demo 4

IE sucks

As some browsers don't support clip-path we've added a test for it in Modernizr and are hiding the box when it isn't supported as the box containing a rectangular image just looks broken. Adding this to the SCSS for the :before and :after is the easiest way to solve it.

display: none;
.clippaths & {
  display: block;
}

Further Reading

Clippy by Bennett Feely is an excellent tool for creating clip paths, and this article on CSS Tricks has a variety of clipping & masking techniques.