Generated Content by David Storey

Creating an angled split feature area with CSS transforms

For an upcoming project I’m working on, I needed to have a feature area that showcased two things equally. The easy option would have been to show them in boxes, either side by side or one on top of the other. I decided instead to try my hand at a comic book look, where the cells are split diagonally. I also wanted to have a hover effect, so that each cell grew bigger or smaller depending on which cell was hovered.

CSS has traditionally not been good at things that are not square (or rounded with border-radius), but it is possible with minimal extra markup. I was speaking to Simurai and he suggested using skew to skew the box, then skew the contents back again. That idea worked and formed the basis of the technique, along with a bunch of other fiddling.

The final result

The final result looks like so:

And when hovering the first box this happens:

Conversely, hovering on the second box makes the first one smaller.

Try out the split feature demo to see it in action.

How it works

The main tricks are to place two divs (or elements of your choice) on top of each other. The first div requires a wrapper element, but the second does not. The wrapper is skewed at the angle you desire, and the child div is skewed back so that the content isn’t slanted. The child is then set to a width smaller that the first div and the overflow is hidden.

The HTML

<div class="box sunrise"><!-- contents --></div>
<div class="slider">
    <div class="box sunset"><!-- contents --></div>
</div>

The CSS

The two boxes are sized the same and decorated:

.box { 
    width: 880px;
    height: 330px;
    border-radius: .5em;
}

The box with the sunrise image is set to use position: absolute to remove it from the flow, so that the sunset box is placed on top of it. It is also styled with a box-shadow and a background image.

.sunrise {
    position: absolute;  /* remove from flow so sunset is placed on top */

    background:  url(sunrise.jpg) no-repeat;
    box-shadow: 0 0 10px rgba(0, 0, 0, .7);
}

The wrapper element around the sunset box is skewed by the required amount, and a transition is set up. An initial width is set and the overflow is hidden, so that only half the contents of the sunset div is shown.

.slider {
    /* set initial width */
    width: 520px;
           
    /* hide the content that overflows (to allow second box to show through) */
   overflow: hidden;
   display: inline-block;
           
    /* skew container so that it has angled edge, and set up transition */
   transform: skewX(-20deg);
   transition: width 1.2s ease-in-out;
}

The sunset div is skewed back by the negation of the angle the parent was skewed, so the contents are straight rather than skewed at an angle. A background image is also set like the sunrise box. As the parent has a skew applied, we need to set a left margin to move the contents and the background image away from the left edge. Otherwise it will be clipped out by the hidden overflow.

.sunset {
    /* skew back by negative of parent’s skew so contents is upright */
    transform: skewX(20deg);
    margin-left: 76px; /* give margin to push content away from left slanted edge */
   background: url(sunset-elephant.jpg) no-repeat;
   pointer-events: auto;    /* allow pointer events for the box */
}

Due to applying a left margin above, there will be a space on the left side. This can be removed by setting a negative left margin of the same value on the wrapper. We can also set pointer-events to none so that the hidden part doesn’t cause the hover to fire. We also need to remember to set the pointer-events back on the sunset div, so the visible part can still be hovered (see above).

.slider {
    …
    /* give negative margin to remove gap caused by left hand skew */
    margin-left: -76px;
           
   /* hide pointer events for unseen content */
   pointer-events: none;
}

Now all this is set up, the only thing left is to apply the hover. As the transitions have already been set up, we just need to change the width when hovering. As the second box (sunrise) is actually first in source order, we can use am adjacent sibling combinator to make the sunset div smaller when the sunrise div is hovered.

/* make first box bigger on hover, and smaller when hover second box */
.slider:hover {
    width: 760px;
}
        
.sunrise:hover + .slider { 
    width: 250px;
}

That is more or less all there is to it. I’m sure there are probably ways with less markup or CSS, but this way works for what I need it for. The main drawbacks is the need for a wrapper div (can probably get away without it, depending on what content you have in the boxes) and the edge is not anti-aliased in the browsers I‘ve tested (Opera is particularly funky, but the strips make a unique effect).

If you didn’t try it out before, check out the demo. Alternatively, try out the demo and view the source on Dabblet.

  1. jalbertbowdenii reblogged this from dstorey
  2. codesnips reblogged this from dstorey
  3. vestride reblogged this from dstorey
  4. experience-ss reblogged this from dstorey
  5. ryanohara reblogged this from dstorey
  6. e110c0 reblogged this from dstorey
  7. thelastguest reblogged this from dstorey
  8. hiqus reblogged this from dstorey
  9. dstorey posted this