12

I'm going to convert this PSD image to CSS. I've multiple h2s in multiple pages, so the inner text lenght and background-color may vary. Therefore the background should automatically adapt to "any" length.

skewed background demo

So far, the markup is something like:

<h2 class="sub-heading lab-heading">Laboratori</h2>

I may eventually wrap the inner text into a <span>, but keeping a semantic valid markup without any additional element would be ♥ly.

The inner text is rotated, but it's not mandatory. What i'm focusing on now is the skewed background.

I'm open-minded to any solution using scaled background pngs (eg. background-size:cover), pseudo-elements, canvas etc. But it must be modular.

Thanks a lot for any suggestion.


[update] A graphical example of what i'm looking for:

i'm not a graphic demonstration


[important note] Behind the h2 there's an irregular pattern (not a "solid" color background)

Giona
  • 20,734
  • 4
  • 56
  • 68
  • +1 for a good question... I can't figure it out. CSS3 shapes doesn't quite get the job done, not exactly how you want it. I have a feeling this is going to have to be done in javascript. – Michael Feb 05 '13 at 18:24
  • What browsers do you need to support? – dave Feb 14 '13 at 13:02
  • @dave IE9+, i'll add a simple fallback for IE8 – Giona Feb 14 '13 at 13:04
  • I see no way to do this with an irregluar pattern as the background. Are you still interested in a way to achieve it with a solid background-color and no #fff for the cut out edges? – dave Feb 14 '13 at 13:20
  • Mmmh thanks but no thanks @dave , that's what MiG's answer does... – Giona Feb 14 '13 at 13:22
  • More experimental than a working solution, I think that can be done with svg clipping from the CSS. see: [http://people.mozilla.com/~roc/SVG-CSS-Effects-Draft.html]. I think that right now only works in mozilla and canary – vals Feb 14 '13 at 17:40
  • Could be an option, on the same topic this [blog post](http://thenittygritty.co/css-masking) explains how to already apply masking cross-browser. But as you said it's still experimental, and i'm not willing to add so much extra code – Giona Feb 14 '13 at 17:49

7 Answers7

5

For anyone who's interested, here's my temporary solution: live demo.

I used this sprite image:

skewed bg sprite

html:

<div class="container">
<h2 class="sub-heading"><span class="sub-heading-txt">Short title</span></h2>
</div>
<div class="container">
<h2 class="sub-heading"><span class="sub-heading-txt">A bit longer title</span></h2>
</div>
<div class="container">
<h2 class="sub-heading"><span class="sub-heading-txt">A damn long title is here!</span></h2>
</div>

(the .container div is only needed for variations)

css:

.sub-heading, .sub-heading:after, .sub-heading:before {
    background:url(tha-sprite-url.png) 0 0 no-repeat;
}

.sub-heading {
    position:relative;
    display:inline-block; clear:both;
    margin-left:31px; padding:0 18px 10px 0;
    font-size:25px; font-weight:normal; color:#FFF; line-height:47px;
    background-position:0 -75px;
    background-size:100% 282px; /* the sprite's height */
}

.sub-heading:before, .sub-heading:after { content:" "; position:absolute; top:0; }
.sub-heading:before { left:-31px; width:31px; height:57px; }
.sub-heading:after { right:-12px; width:12px; height:42px; background-position:-150px 0; }

.sub-heading-txt {
    display:block;
    -webkit-transform:rotate(-2deg); -ms-transform:rotate(-2deg); transform:rotate(-2deg);
}

/* variations */
.container { margin-bottom:10px; }
.container:nth-child(3n+2) .sub-heading { background-position:0 -150px; }
.container:nth-child(3n+2) .sub-heading:before { background-position:-50px 0; }
.container:nth-child(3n+2) .sub-heading:after { background-position:-175px 0; }
.container:nth-child(3n+3) .sub-heading { background-position:0 -225px; }
.container:nth-child(3n+3) .sub-heading:before { background-position:-100px 0; }
.container:nth-child(3n+3) .sub-heading:after { background-position:-200px 0; }

Works on IE9+

Unfortunately, background-size property doesn't support an "inherit" value, so the actual sprite's height must be set in the css :-( I'm still looking for a more efficient solution.

Giona
  • 20,734
  • 4
  • 56
  • 68
3

With the combination of CSS shapes, positioning, :before and :after selectors I've managed to make the container expandable to any content. However, this approach only works in modern browsers and it seems that there's no proper solution without js. Also, the use of svg could be really handful in this case but again you're limited to the browser compatibility.

Here is the demo using pure CSS: http://jsfiddle.net/qaWKX/

EDIT

The use of svg turned out to be useless without an extra JS function. So I dropped this approach. However, the only proper solution relies on CSS3 but without the use of :before and :after selectors. My previous approach was relying on creating pseudo elements that hide both sides of the h3 title. Hiding is not enough when there's no solid color for the background.

With this logic I needed to have a background that will combine transparency and solid fill. The answer was on CSS3 linear-gradient background.

In details: 1. I rotated the h3 title 2. I masked the top area with its container (top:-value or margin-top:-value) 3. I set 2 linear-gradient background images to each side

Here's the demo: http://jsfiddle.net/P5gLE/1/

otinanai
  • 3,987
  • 3
  • 25
  • 43
  • Cool! But i can't use the white border because the h2's background is an irregular pattern... p.s. no need for -moz-transform – Giona Feb 14 '13 at 13:01
  • I understand the limitations of the CSS solution, so I recommend utilizing `svg`as a `background-image` and setting the `background-size` to `100%`. The bigger your `svg` dimensions, the better quality at resizing. And don't forget that it's vector so it's up to browser's svg engine how well it's loading the `svg` background. Here's a demo: http://jsfiddle.net/sSaBJ/1/ Note: The `svg` file is just 481 bytes! – otinanai Feb 14 '13 at 13:59
  • 1
    hehe thanks, that's what i'm actually doing with a png image (check my own answer, just posted) to avoid transparency issues with svg. Also, i had to cut the right and left sides to preserve the "skeweness" – Giona Feb 14 '13 at 14:04
  • Nice one for a temp solution. The only problem in each solution (either yours or mine) is that bg color is not editable through css. – otinanai Feb 14 '13 at 14:08
  • Yup :-( also, the sprite's height must be set in the css. i guess the only way to achieve it in a really modular way atm is to use canvas, but i'm a total noob there... – Giona Feb 14 '13 at 14:11
  • This is the top voted answer and the bounty ends in 2 mins, so i'll award it to you ;-) – Giona Feb 14 '13 at 22:19
  • Thank you sir! I appreciate it. However, I'm still working on the svg solution because I think it's the most convenient and compatible. And most important: it can be controlled with css. So, it's a matter of time until I figure out a way to wrap text in an svg shape. If you're going to use canvas you still don't avoid js so I'm not going into this direction. I'll come back to you as soon as I get it sorted and modulized. – otinanai Feb 14 '13 at 23:56
  • Wow thanks for your commitment! I'll wait for your next idea then! – Giona Feb 15 '13 at 01:09
  • 1
    Cool! To avoid the white middle line, just set `background-size: 51% 100%;`. Also, instead of `display:table` and `table-cell` i'ld go for `inline-block` (more consistent across browsers). [Check my version of your edit](http://jsfiddle.net/gionaf/6y8h4/). Unfortunately css gradients are not supported by ie9 :-( great job anyway! – Giona Feb 17 '13 at 18:42
1

here is the html:

<br>
<div class="scewed-shape">
    <div class="text-align">here is a very long text adsadsad</div>
</div>
<br>
<br>
<div class="scewed-shape">
    <div class="text-align">this one is shorter</div>
</div>

and here is the css that makes the custom shape:

.scewed-shape {
    display:inline-block;
    -webkit-transform: perspective(500px) rotateY(34deg);
    -ms-transform: perspective(500px) rotateY(34deg);
    left: -25px;
    height: 0;
    border-style: solid;
    border-color: red transparent transparent transparent;
    border-width: 70px 50px 0 50px;
}
.scewed-shape .text-align {
    position: relative;
    top: -25px;
}
David Tolioupov
  • 173
  • 2
  • 9
  • Really thanks for taking the time to build the plugin, but i can achieve the same result without javascript just by setting `inline-block` to `.scewed-shape` ... [demo](http://jsfiddle.net/gionaf/f4gA7/). It's a good starting point, but the shape in my demo is more complex. Oh, you only need -webkit and -ms prefixes for `transform` ;-) – Giona Feb 08 '13 at 21:26
  • the point is that no matter how complex is your shape you can use this bit of javascript to adjust the width and you should be all set – David Tolioupov Feb 08 '13 at 21:40
  • Mmh yup, somehow this can be a piece of the puzzle. But i still need to build that shape with css or resizing/slicing images, in a way that the shape itself auto-adjusts. That's the point of the question.. – Giona Feb 08 '13 at 23:05
  • The shape is totally fine, thanks a lot. But with this method the text becomes distorted too, and the custom font i'm using won't display well :-( anyway, if you change your original answer with the new demo i'll upvote it ;-) – Giona Feb 09 '13 at 14:39
  • @Giona , I changed the original answer – David Tolioupov Feb 09 '13 at 23:35
1

I don't think it is possible to do with just the h2. The problem occurs with the different angles of the skewed sides, meaning you need a 'container' for the skewing and transforms.

Given your example, I came up with the following:

http://jsfiddle.net/Cbx2q/1/

As you will see, this is has a couple of maintenance problems:

  • 'Magic Numbers' - these will need tweaking dependent on the skew + size you choose.
  • Font rendering with the transform is somewhat worse.

Otherwise, it seems to work. The best solution outside of using pseudo-elements and CSS3 is likely to stick with plain old images for the background of each menu item.

Hux
  • 3,102
  • 1
  • 26
  • 33
  • The idea would be perfect, but i don't have a solid background color unfortunately, so the #fff triangle with pseudo-elements won't work in my case. Good job anyway, upvote – Giona Feb 14 '13 at 10:44
  • @Giona I didn't notice the solid background colour bit... You may be better off just taking a solid background of the entire menu, then a background image for each menu item. The skewed text also means you could up with the text in images for decent IE support. Thanks. – Hux Feb 14 '13 at 10:58
  • It's not for menu items but for sub-sections titles in articles, which are written by different authors via cms. So i can't make an image for each and every new sub-heading. The article background is a wooden irregular pattern ... Maybe i should just kill the photoshop designer ;-) – Giona Feb 14 '13 at 11:32
  • The only alternative I can think of is using `canvas` or SVG if possible to create and display the background and possibly text as well. Not sure how this would behave with the transparency though. – Hux Feb 14 '13 at 11:52
  • I did some test cases with SVG few months ago, transparency is buggy even in modern browsers (sigh). canvas can surely be an option, but i really don't know where to start – Giona Feb 14 '13 at 12:59
0

What about using CSS shapes? I haven't worked with them a ton, but it seems like a good place to start.

http://css-tricks.com/examples/ShapesOfCSS/

  • That's what I looked at above, but it's not a very ideal solution, positioning the text would prove to be difficult. – Michael Feb 05 '13 at 19:19
  • 2
    CSS shapes use borders to achieve the effect, and since border-width can't be set using percentages, the technique won't work for this use case as it's not possible to get them to scale to different text lengths. – Jeff-Meadows Feb 05 '13 at 19:48
0

One easy solution I can think of is using 3 elements(I would use divs) for the three different bottom angles of the shape, having the left and right ones have a fixed size and the middle one simply scale with the text(headline) contained in it. Maybe not the most elegant solution, but it would definitely work. A downside is that you need a lot of images, especially if you want to have different coloured shapes. (I know of no way to colour a background image).

Though, if the space around the shape has a solid background colour, you could actually set the background colour of the 3 elements to the colour you want and have the actual images you use have the same colour as the background as negative space, being transparent where you want the actual shape.

Also, if you really do not want more elements than you need to, you can always use the :after and :before selectors to fake it.

amulware
  • 412
  • 2
  • 15
  • Sorry, I should have specified that the color variations will be handled by a second css class, which varies in each h2. Unfortunately, the container's background is an irregular texture, so i need the skewed bg to be transparent. Your idea may be valid, i'm not sure if the "pieces" would fit well though. Thanks for your suggestions! – Giona Feb 05 '13 at 21:51
0
<!--[if lt IE 9]>
<script src="http://ie7-js.googlecode.com/svn/version/2.1(beta4)/IE9.js"></script>
<![endif]-->

The above code will make IE 5.5 through 8 run like a modern compliant browser, as far as styling/functionality in the page is concerned. This script is specifically made to address CSS/rendering errors in past versions of IE.

Here is documentation on the script: http://www.charlescooke.me.uk/web/lab_notes/ie7_script.html

This is kind of an "IE Fallback", but a better way to approach the issue. Instead of making a ton of versions of the content to render the exact same way using different browsers, this simply forces modern compatibility upon early versions of IE.

I've used this script in the past to fix similar CSS rendering errors. This specific script above is to update IE5.5-8 up to 9. If you deliberately wish to upgrade IE5.5-7 up to 8 (no idea why you'd need to, but if you so desire), additional scripts at the URL below can do this.

Here is Google's page and into docs on it (includes the link above on this page as well) http://code.google.com/p/ie7-js/

Arman
  • 135
  • 1
  • 10