100% height block with vertical text
Asked Answered
S

4

16

I have a block of a variable height in which I want to put another block with 100% height and vertical text (bottom-to-top direction) and stack it to the left side of the outer block. Is there a way to achieve it with CSS transforms but without width and height calculations in JS?

Sketch

This is what I could get so far:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<style type="text/css">
.block1 {
    border: 4px solid #888;
    height: 120px;
    width: 200px;
}
.block2 {
    height: 100%;
    border: 4px solid red;
}
.msg {
    display: inline-block;
    white-space: nowrap;
    font-family: Verdana;
    font-size: 14pt;
    -moz-transform: rotate(-90deg);
    -moz-transform-origin: center center;
    -webkit-transform: rotate(-90deg);
    -webkit-transform-origin: center center;
    -ms-transform: rotate(-90deg);
    -ms-transform-origin: center center;
}
</style>
</head>
<body>
    <div class="block1">
        <table class="block2">
        <tr>
            <td>
                <div class="msg">Hi there!</div>
            </td>
        </tr>
        </table>
    </div>
</body>
</html>

My test

You can see that the inner block's computed width is the same as the text width before rotation.

UPDATE:

Here is the picture of what I want to get in the end:

enter image description here

It's a horizontal stripe with items stacked to its left side, and with a vertical header block. Stripe's height is variable, so items should adapt and the header's text should remain centered.

Stadium answered 1/6, 2012 at 1:36 Comment(0)
C
26

I believe you were only using a <table> because it seemed to be the easiest way to achieve what you were looking for, so I cut it out of the equation and used semantic HTML instead. If there was another reason, I apologize in advance and you should be able to port the styles over to use a <table> instead.

See the jsFiddle demo to view the code in action. Or, continue on to the code:

HTML

<section class="wrapper">
    <header><h1>Test</h1></header>
    <article>Text.</article><!--
    --><article>More text.</article><!--
    --><article>Photos of cats.</article><!--
    --><article>More photos of cats.</article>
</section>

CSS

.wrapper {
    margin:1em;
    position:relative;
    padding-left:2em; /* line-height of .wrapper div:first-child span */
    background:#fed;
}
.wrapper header {
    display:block;
    position:absolute;
    top:0;
    left:0;
    bottom:0;
    width:2em; /* line-height of .wrapper div:first-child span */
    overflow:hidden;
    white-space:nowrap;
}
.wrapper header h1 {
    -moz-transform-origin:0 50%;
    -moz-transform:rotate(-90deg) translate(-50%, 50%);
    -webkit-transform-origin:0 50%;
    -webkit-transform:rotate(-90deg) translate(-50%, 50%);
    -o-transform-origin:0 50%;
    -o-transform:rotate(-90deg) translate(-50%, 50%);
    -ms-transform-origin:0 50%;
    -ms-transform:rotate(-90deg) translate(-50%, 50%);
    transform-origin:0 50%;
    transform:rotate(-90deg) translate(-50%, 50%);
    position:absolute;
    top:0;
    bottom:0;
    height:2em; /* line-height of .wrapper div:first-child span */
    margin:auto;
    font-weight:bold;
    font-size:1em;
    line-height:2em; /* Copy to other locations */
}
.wrapper article {
    display:inline-block;
    width:25%;
    padding:1em 1em 1em 0;
    vertical-align:middle;
    -moz-box-sizing:border-box;
    -webkit-box-sizing:border-box;
    -ms-box-sizing:border-box;
    -o-box-sizing:border-box;
    box-sizing:border-box;
}

How it works

The <header> is set to the height of .wrapper and has it's width set to 2em (value of line-height for the <h1>). Then, the <h1> is vertically aligned (with top:0;bottom:0;height:2em;margin:auto; [2em is also from line-height]). Once the <h1> is vertically aligned, it is rotated counter-clockwise 90 degrees by the middle of its left side. In order to make the <h1> visible again, it is translated 50% vertically (to pull it back onto the screen horizontally) and -50% horizontally (to vertically align it). And yes, the wording is correct--everything just gets confusing once you rotate by [-]90 degrees ;)

Gotchas

  • Only a static "height" is supported for the <h1>. In this case, only 1 line is supported.
  • Wrapping will not work (I've actually disabled it in this example), so anything that doesn't fit in the height of .wrapper will be hidden.
Chronicle answered 6/6, 2012 at 4:35 Comment(7)
Took one look at this problem, and immediately thought of this kind of solution. Great answer! Curiosity though, using the code you've provided, how might you go about "right-aligning" (or top-aligning, I suppose) the text that's been rotated?Catalysis
Turns out just removing margin: auto; will do the trick, and to change the positioning vertically, you can just adjust the margin-top/bottom properties.Catalysis
@spatar, is this answer missing something for the bounty? Or just waiting until the end to assign it?Chronicle
@Nightfirecat, actually, it would be better to: remove bottom:0; and margin:auto;, change transform-origin to 0 0, and change transform to rotate(-90deg) translate(-100%, 0) for .wrapper header h1. See top-aligned example. To align it to the bottom, do the same thing, except remove top:0; instead of bottom:0;. See the bottom-aligned example.Chronicle
@bfrohs, the answer is absolutely worth bounty but when I try to give it to you I see a message: "You may award your bounty in 27 minutes" (yesterday it was 11 hours)Stadium
Didn't think of using transform-origin. Nice, bfrohs!Dormitory
Works great. ThanksCornejo
D
0

After looking at the transform styles more thoroughly, it doesn't appear so. You would need to know the precise height of the outter div.

Dormitory answered 2/6, 2012 at 1:6 Comment(2)
Most likely you are right. But I will wait couple more days. Thanks.Stadium
No worries. If someone else does post a solution, I'll be very eager to read it!Dormitory
B
0

The best I could come up with is this: http://jsfiddle.net/EwgtT/

The variable height of block1 won't be a problem, but the variable height of your message is; it will always start at the bottom.

Edit: Updated, so it works well in FF and IE: http://jsfiddle.net/EwgtT/2/

Beeler answered 5/6, 2012 at 17:4 Comment(1)
I tried your code in Firefox and the text appears at the bottom of the page, out of the red block.Stadium
G
0

I came up with this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<style type="text/css">
.block2 {
    width: 100%;
    border: 4px solid red;
}
.msg {
    display: inline-block;
    white-space: nowrap;
    font-family: Verdana;
    font-size: 14pt;
}
.block1 {
    border: 4px solid #888;
    -moz-transform: rotate(-90deg);
    -moz-transform-origin: right top;
    -webkit-transform: rotate(-90deg);
    -webkit-transform-origin: right top;
    -ms-transform: rotate(-90deg);
    -ms-transform-origin: right top;
    text-align:center;
}
</style>
</head>
<body>
    <div class="block1">
        <table class="block2">
        <tr>
            <td>
                <div class="msg">Hi there!</div>
            </td>
        </tr>
        </table>
    </div>
<style>
.block1{
width:500px;
margin-left:-500px;
}
</style>
</body>
</html>
  • switched the transformation to the outer element,
  • then used width attribute to define the height at the bottom of the page (when you play with that, you are actually playing with the height there.)
  • and for the empty left space visible after rotation, I used the variable width (height) as negative margin.

You can see it here: http://pastehtml.com/view/c0hl7zxci.html

Good answered 5/6, 2012 at 17:8 Comment(1)
Actually I don't want to rotate the outer div because the idea was to stack more divs inside with regular (not rotated) text. Sorry if I wasn't clear. I'm attaching a new picture to the question to display what is my final goal.Stadium

© 2022 - 2024 — McMap. All rights reserved.