I am about to start a large, design oriented website that just has to be pixel perfect and as good as possible.
The problem is how to keep consistent spacing between elements in a container like this:
Currently I create all containers with
padding: 40px 40px 30px and every element with margin-bottom: 10px;
This solves the problem nicely, but every element, including headings, has to have exactly 10 pixels below itself and zero pixels above itself.
Currently I also use https://github.com/kiskadigitalmedia/kiskabricks_wedgecss (div with set height) to create additional vertical whitespace if the design calls for it. Like here:
This is the code for the above example:
<div class="card">
<h1>Heading 1</h1>
<p>Paragraph text</p>
<div class="wedge-2x">
<a class="btn">Button</a>
</div>
Does this approach make sense? Is there any better way to guarantee consistent spacing of elements inside a container? Any input appreciated.
I would do it like this:
<div class="card">
<h1>Heading 1</h1>
<p>Paragraph text</p>
<a class="btn">Button</a>
</div>
CSS:
.card {
padding: 40px;
box-sizing: border-box;
}
h1, p {
margin-bottom: 10px;
}
.btn {
margin-top: 20px;
display: inline-block;
}
If you want for example a 10 pixels margin above & below your elements, an option could be something like this. All the elements inside the class="card" will be affected by the same margins.
.card{
padding: 40px;
}
.card h1, .card p, .card .wedge-2x, .card a{
margin: 30px 0px;
}
It depends on how much flexibility you want to have.
your solution looks like a good start. maybe try and use siblings selectors too?
so in scss you'd have something like:
.card {
padding: 40px;
h1 ~ p,
h1 ~ a { margin-top: 10px; }
}
Or use + instead of ~ if you want a more specific HTML structure.
Or you could rewrite this using margin-top for all elements except for the first one, by using :first-child { ... }
Our web service has been hit with some Zalgo text and I'm trying to come up with a good solution for the future. Our policy is to accept all user input and save it in permanent storage (we correctly encode the input for our backend so this part is okay). During the output phase, we run the original user input through filter/parser with a whitelist to avoid XSS attacks and other mayhem. Lately some users have found the world of Zalgo and they just love to cause some trouble to other people with that.
As I see it, Zalgo text is just a piece of Unicode text that leaks out of the intended container. As a result, I think automatically removing all complex combining characters is too drastic defence. Does anybody know a CSS trick to force the Zalgo text to be contained in a given parent element without some nasty side-effects?
For example, if I have
<section class="userinput">
... user input here ...
</section>
how can I make sure that the user input does not leak outside the borders of section.userinput? I guess overflow: hidden or clip: rect(...) could be the correct answer, but do you know something better for this use case? Preferably I could still use section.userinput { max-height: 200vh; } or something similar to avoid users from creating artificially long comments. If some comment were longer than 200vh, it should have a scroll bar for that comment alone. Normally there should be just a single scroll bar for the whole page.
Note that I'm trying to combat the problem in visual domain only. I'm perfectly happy to accept any valid UTF-8 sequence as user input and I'm okay if a messed up user comment results in that user comment looking like crap. I'm only trying to avoid that crap overflowing all over the place. Specifically, I'm not trying to block the zalgo text or to filter zalgo-like text before display.
After testing an example case with Firefox and Chrome, I would say the best option is to use declaration overflow: auto. Using overflow: hidden would make sense only if possible scrollbars are considered worse than losing user content.
The overflow: auto allows falling back to scrollbars automatically if content does not fit and it still forces clipping to selected element.
The declaration clip: rect(0,auto,auto,0); is no good because it only works with position: absolute; and without overflow: visible.
See an example without overflow: auto for an comparision.
Above examples inlined here as snippets:
An example without safeguards against Zalgo text:
body
{
background: #ccc;
color: #000;
font-family: sans-serif;
padding: 4em 1em;
}
section.userinput
{
margin-top: 0.5em;
padding: 0.1em 0.25em;
background: #fff;
border: solid #ccc 0.1em;
border-radius: 0.5em;
font-size: 120%;
}
.v1 section.userinput
{
overflow: auto;
}
.v2 section.userinput
{
position: absolute;
clip: rect(0em,auto,auto,0em);
}
<body class="">
<section class="userinput">
Some real content here.
</section>
<section class="userinput">
T̠̬̘̯̙̲̪̪͇̜̭̣̘̟̲͇̳̬͕̖̜̯̘͉͈͉͎̱͓̣̰̳̳͉̙̯̙̰͚͇͎͕̘̯̳̞̲̼̱̖̩͙͕̤͂̋͌ͤ̒ͬ̀͒͂͒ͩ̌͗̋̓ͭ́̀̿͒ͣͮ̓̋ͭ͊͒͐ͩ̆̓͂ͫ̐͂̇͛͑̓̚ͅẽ̗̙͚̮̭̮̬̠͈̻̦̭̭̳̹̯̹̦̔̌ͯ͂̎̈̊̍ͣ̿̈̈̿̄ͦͭ̍͑̽̎̅͛͗͐ͬ̂̊̽̌̎̋ͭ͆̈́̓ͦͦ̑͛ͯs̭̠͖̝͙̩̫̫̥̦͚̝̼̣̥̗ͣͦ͑́͐ͭ͊ͧ̽͐̈̔͛ͨ́̎̔ͤ͐͒̓̀̅̈́̊̋͋̀̿̎͒̉̽͂ͮͬt̾͒̂̽̐ͪ̆̾ͮ͌̽͛̌͒̔ͧ͗̿ͩ̄̿̿̌ͪͩ̊̏͑͌̀̋ͩ͆ͣ̑̏́̽̐͐̔ͪ̓̓ͭ͆ ̯̘͙̠̦̩̝͎̭̖̪̗̞̖̟̲͖̥͙͕̟̝̹͎̽o̼̮̭̞ͯͬ̀͐͗̿ͣ͛ͮͭ̎ͨ͒̌̾̐̉̍͗̎̈́̆ͪͦ̌ͧͦ̓ͨ̐ͯ͒͑͛ͯ̽ͅf̝̪̼̠͎͇̹̝̙̰̟̼͎̱͂ͩ̈́̌ͬ̒ͧ̽̅̉ͧ́͒̒͊ͦͭͭͭ͗́̽ͦ ͚̝̝̠̪͍̰̺̳̫̭͎͔̭̟͍͎͇͎͈͔̠̬͇̦͈̟̰̱̹̲̰̭̲̭̺̜͚̰̹̮̣̤̲̪̙̞͇̦͙͆ͪͨ̐ͨ̽̒͛ͩ̐ͤ͌̂́͒̌ͭͩͦ̎́̈ͬ̓̑̔͐̎͒̔̄ͥ̏ͥͯͧ͐ͪͧͥ̂ͬ̒̀̉̓ͭ̚ͅͅͅͅZ̘̥̲͍̠͎̱̺̘͈͍̟̤̠̮͖͉͕̙̩̲̣̠͎̥̣̜͚̜͕̻͔̰̞̫̭̹͕͙̝̠̮̣̰ͤͦ̍̓ͪͥ̒ͩ̋͆̍͋̽̅͗̈ͨ̂ͨ͋̔̔̓ͪͣ̅̇̏͒ͬ͐ͩ̇ͨ̋ͣ̌̔ͨ́ͪ̔̾̄ͤ̅͑̚ͅA̞̜̺̣͓̼̭̭͈̳̞͚̭̭͕̺͉̜̗̼̣̩̪͂ͯ̈́̍̍͛ͮ̂ͯ̽̎ͬͯ͆̋͌̍͐̌͗ͤ̒ͤ͊̐̈́ͧ̓̇ͬͦ̾ͭ̐̆̚ͅͅͅL̪͉̬̦̝̠̲͖̘̮̙̳͓͇͇̪̱͉̱͓̺͙͓̲̇́̍̽̇̎͊̍̐ͩ̔̋́ͬ̍ͮͫͮ͗̍͋ͭͯ̑̉̈́̄̾̂̀͆̅͑̽̃̚G̣̺̼͔̺̖̣̥̝̰͙̖͖̮̻̩͓̞͈̜̗̤̺̥̻̞͇̩͕̲̙̝̲̤̤̜̐͗͐ͦ̉͐͗ͩ̿ͩ̑ͫ̍͛̄ͦ̔̚O͇͎̬̰̦̜̻͔͇̖͇̞̪͉͉͔͕̥͇̬̮̰̠̟̤̰̹͖̗̺̙͍ͮͨ̿ͪͯ̈́ͫ̔̽̃̀ ̺͕̠̰̝͎̰̟̠̲̗͈̬̥͈͎̺̮̗͍̺͚̟̠̙̠̜̘̹͉̖̤͉̫̰̱̭̠̲̲̗͒ͥͯ̎͐ͨ̓̓ͮ͒ͧ̒̾́̍̍ͦͥ̈́͒͊̃̓̈̈́̀ͮ̂ͪ̓̄̏ͫ̄̓̓̿̓̔̋̎ͧͪͩͪ͋ͫt̘̥̳̺̳̟̯̜̱̯̬̣̣͔̬̟͈͖̗̹͉̫̯́̋͒͂̈́̎͐̇́ͫ̒͛ͥͦ̐̿͂͒͗̃ͮ͒ͪ̌͆̏ͯ̏ͯ̊ͣ̾̃͋ͩ̃̿͐e̹̠̻̟̪̪͎̭̭͎͎̮̹̬̮̪̓̑ͨ̐͐̈́̓ͤͦ͂̿̅͋ͭ̑̓ͬ͐͐ͤ͐ͪ̒ͥ̀̈́ͪ̇̆ͤ̏̏̄̾̌͒ͬ̊ͬ͛̄̄̌̍͋ͥͅͅx̪͇̞̫̰̠͓̣̻̯̞̭̙̝̣͉̱̘̤͇̦̘̙̥͚̫̩̲̘̻͈͉̱͙͇͙ͫ̐̌͛̓͛ͨ͒̂t̩̖̮̙̻ͬ͗͛̍̅̌ͧ͒ͫ̓ͮ̈͒̾ͮͣͮͨͪ͆ͥ̐̍ͮ̽̅̈́̿ͫ͐̍̉ͦͮ͆͗̔̎̿̇ͧ̋ͨͮ̐̓͑̽̑ͤ̊̚̚ͅ ̝͔̺̩͔͈̰͈̣̫̤͉͚͇̟̹̘͔͇̥̘̘̝͛͛̒ͭͣͮͥͦ̿̏ͥͦ̀͂̾͆ͯͧͮͤ͌̌́͗ͨ̎̒ͬ̈́ͧ̊ͨ̓͂̾̉͐ͦ̃̃̚ͅẖ̰̠̮͓̣̯̭̥̹̜̟͍͍͇̀ͧ̽͑̄͊̋̐͋ͨ̔ͭͬ́̀̐͌͗ͥ̓̇͗̂̊ͅe͇͙͕̺̖̰̟̠̩̘̪̳̻̳͉͔̺̳̲̦̘̞̬̬̝͓̬̣̟͕̘͓̬̍͗̋ͮ͑ͣ͗̓̓̎̈̃̾̊̃ͧ̊ͪ̃̀͋̋̄͑̈́̂́͒̔̎̎ͥ͛͌̃͒̈́ͤ͛ͬͫͪ̚r͉̮̼̙̩͖͍̗̣̘͚̭̩͙͙̻͓̦̱̣͉̮̲͇̥͉͚̲͕͖̩̦̫̪̬͔̟͔̦̻̼̼̫̫̯̣̮͈̺͓͖̬̂̾͛̉̆̍ͥ̈́̓̆ͫ͑̄̔̅̈̏̅̓ͨ͐̊ͮ̋̈́ͣͮ̋̓̾ͤ͊ͬ̀̑ͣ͊̇͌ͯ̚ͅḙ̲͍͙͕̯̘͓͔͔͈̹͈̗͎͕̬̖̟̖͚̳͎̖ͩ͊̃ͫ̔̓͒͗ͩ͋̂ͩͩͧ̍͛̿͒ͩͅ.̯̗͗̑̍̑͗ͫͦͦͪͪͧ́̾̓̌̉͑̊̌̿̓ͫ̆̑̽̽ͪͦͨ͌ͦͨ̓
</section>
<section class="userinput">
Some another real content here.
</section>
</body>
And example with safeguards against bleeding zalgo text:
With overflow: auto applied to each user input container (the only differences is the v1 class in body element; you could also try class v2 to understand why it doesn't work for this purpose):
body
{
background: #ccc;
color: #000;
font-family: sans-serif;
padding: 4em 1em;
}
section.userinput
{
margin-top: 0.5em;
padding: 0.1em 0.25em;
background: #fff;
border: solid #ccc 0.1em;
border-radius: 0.5em;
font-size: 120%;
}
.v1 section.userinput
{
overflow: auto;
}
.v2 section.userinput
{
position: absolute;
clip: rect(0em,auto,auto,0em);
}
<body class="v1">
<section class="userinput">
Some real content here.
</section>
<section class="userinput">
T̠̬̘̯̙̲̪̪͇̜̭̣̘̟̲͇̳̬͕̖̜̯̘͉͈͉͎̱͓̣̰̳̳͉̙̯̙̰͚͇͎͕̘̯̳̞̲̼̱̖̩͙͕̤͂̋͌ͤ̒ͬ̀͒͂͒ͩ̌͗̋̓ͭ́̀̿͒ͣͮ̓̋ͭ͊͒͐ͩ̆̓͂ͫ̐͂̇͛͑̓̚ͅẽ̗̙͚̮̭̮̬̠͈̻̦̭̭̳̹̯̹̦̔̌ͯ͂̎̈̊̍ͣ̿̈̈̿̄ͦͭ̍͑̽̎̅͛͗͐ͬ̂̊̽̌̎̋ͭ͆̈́̓ͦͦ̑͛ͯs̭̠͖̝͙̩̫̫̥̦͚̝̼̣̥̗ͣͦ͑́͐ͭ͊ͧ̽͐̈̔͛ͨ́̎̔ͤ͐͒̓̀̅̈́̊̋͋̀̿̎͒̉̽͂ͮͬt̾͒̂̽̐ͪ̆̾ͮ͌̽͛̌͒̔ͧ͗̿ͩ̄̿̿̌ͪͩ̊̏͑͌̀̋ͩ͆ͣ̑̏́̽̐͐̔ͪ̓̓ͭ͆ ̯̘͙̠̦̩̝͎̭̖̪̗̞̖̟̲͖̥͙͕̟̝̹͎̽o̼̮̭̞ͯͬ̀͐͗̿ͣ͛ͮͭ̎ͨ͒̌̾̐̉̍͗̎̈́̆ͪͦ̌ͧͦ̓ͨ̐ͯ͒͑͛ͯ̽ͅf̝̪̼̠͎͇̹̝̙̰̟̼͎̱͂ͩ̈́̌ͬ̒ͧ̽̅̉ͧ́͒̒͊ͦͭͭͭ͗́̽ͦ ͚̝̝̠̪͍̰̺̳̫̭͎͔̭̟͍͎͇͎͈͔̠̬͇̦͈̟̰̱̹̲̰̭̲̭̺̜͚̰̹̮̣̤̲̪̙̞͇̦͙͆ͪͨ̐ͨ̽̒͛ͩ̐ͤ͌̂́͒̌ͭͩͦ̎́̈ͬ̓̑̔͐̎͒̔̄ͥ̏ͥͯͧ͐ͪͧͥ̂ͬ̒̀̉̓ͭ̚ͅͅͅͅZ̘̥̲͍̠͎̱̺̘͈͍̟̤̠̮͖͉͕̙̩̲̣̠͎̥̣̜͚̜͕̻͔̰̞̫̭̹͕͙̝̠̮̣̰ͤͦ̍̓ͪͥ̒ͩ̋͆̍͋̽̅͗̈ͨ̂ͨ͋̔̔̓ͪͣ̅̇̏͒ͬ͐ͩ̇ͨ̋ͣ̌̔ͨ́ͪ̔̾̄ͤ̅͑̚ͅA̞̜̺̣͓̼̭̭͈̳̞͚̭̭͕̺͉̜̗̼̣̩̪͂ͯ̈́̍̍͛ͮ̂ͯ̽̎ͬͯ͆̋͌̍͐̌͗ͤ̒ͤ͊̐̈́ͧ̓̇ͬͦ̾ͭ̐̆̚ͅͅͅL̪͉̬̦̝̠̲͖̘̮̙̳͓͇͇̪̱͉̱͓̺͙͓̲̇́̍̽̇̎͊̍̐ͩ̔̋́ͬ̍ͮͫͮ͗̍͋ͭͯ̑̉̈́̄̾̂̀͆̅͑̽̃̚G̣̺̼͔̺̖̣̥̝̰͙̖͖̮̻̩͓̞͈̜̗̤̺̥̻̞͇̩͕̲̙̝̲̤̤̜̐͗͐ͦ̉͐͗ͩ̿ͩ̑ͫ̍͛̄ͦ̔̚O͇͎̬̰̦̜̻͔͇̖͇̞̪͉͉͔͕̥͇̬̮̰̠̟̤̰̹͖̗̺̙͍ͮͨ̿ͪͯ̈́ͫ̔̽̃̀ ̺͕̠̰̝͎̰̟̠̲̗͈̬̥͈͎̺̮̗͍̺͚̟̠̙̠̜̘̹͉̖̤͉̫̰̱̭̠̲̲̗͒ͥͯ̎͐ͨ̓̓ͮ͒ͧ̒̾́̍̍ͦͥ̈́͒͊̃̓̈̈́̀ͮ̂ͪ̓̄̏ͫ̄̓̓̿̓̔̋̎ͧͪͩͪ͋ͫt̘̥̳̺̳̟̯̜̱̯̬̣̣͔̬̟͈͖̗̹͉̫̯́̋͒͂̈́̎͐̇́ͫ̒͛ͥͦ̐̿͂͒͗̃ͮ͒ͪ̌͆̏ͯ̏ͯ̊ͣ̾̃͋ͩ̃̿͐e̹̠̻̟̪̪͎̭̭͎͎̮̹̬̮̪̓̑ͨ̐͐̈́̓ͤͦ͂̿̅͋ͭ̑̓ͬ͐͐ͤ͐ͪ̒ͥ̀̈́ͪ̇̆ͤ̏̏̄̾̌͒ͬ̊ͬ͛̄̄̌̍͋ͥͅͅx̪͇̞̫̰̠͓̣̻̯̞̭̙̝̣͉̱̘̤͇̦̘̙̥͚̫̩̲̘̻͈͉̱͙͇͙ͫ̐̌͛̓͛ͨ͒̂t̩̖̮̙̻ͬ͗͛̍̅̌ͧ͒ͫ̓ͮ̈͒̾ͮͣͮͨͪ͆ͥ̐̍ͮ̽̅̈́̿ͫ͐̍̉ͦͮ͆͗̔̎̿̇ͧ̋ͨͮ̐̓͑̽̑ͤ̊̚̚ͅ ̝͔̺̩͔͈̰͈̣̫̤͉͚͇̟̹̘͔͇̥̘̘̝͛͛̒ͭͣͮͥͦ̿̏ͥͦ̀͂̾͆ͯͧͮͤ͌̌́͗ͨ̎̒ͬ̈́ͧ̊ͨ̓͂̾̉͐ͦ̃̃̚ͅẖ̰̠̮͓̣̯̭̥̹̜̟͍͍͇̀ͧ̽͑̄͊̋̐͋ͨ̔ͭͬ́̀̐͌͗ͥ̓̇͗̂̊ͅe͇͙͕̺̖̰̟̠̩̘̪̳̻̳͉͔̺̳̲̦̘̞̬̬̝͓̬̣̟͕̘͓̬̍͗̋ͮ͑ͣ͗̓̓̎̈̃̾̊̃ͧ̊ͪ̃̀͋̋̄͑̈́̂́͒̔̎̎ͥ͛͌̃͒̈́ͤ͛ͬͫͪ̚r͉̮̼̙̩͖͍̗̣̘͚̭̩͙͙̻͓̦̱̣͉̮̲͇̥͉͚̲͕͖̩̦̫̪̬͔̟͔̦̻̼̼̫̫̯̣̮͈̺͓͖̬̂̾͛̉̆̍ͥ̈́̓̆ͫ͑̄̔̅̈̏̅̓ͨ͐̊ͮ̋̈́ͣͮ̋̓̾ͤ͊ͬ̀̑ͣ͊̇͌ͯ̚ͅḙ̲͍͙͕̯̘͓͔͔͈̹͈̗͎͕̬̖̟̖͚̳͎̖ͩ͊̃ͫ̔̓͒͗ͩ͋̂ͩͩͧ̍͛̿͒ͩͅ.̯̗͗̑̍̑͗ͫͦͦͪͪͧ́̾̓̌̉͑̊̌̿̓ͫ̆̑̽̽ͪͦͨ͌ͦͨ̓
</section>
<section class="userinput">
Some another real content here.
</section>
</body>
I have recently noticed a scroll-behavior property that I can specify in my css. It can take only 2 properties: inherit and initial. I have never heard/seen it before, so I tried to look at it. The problem is that all the links are going into explaining different things about overflow property.
Then I tried to test it.
<div id="scroll">
<div id="inside">
</div>
#scroll{
width: 100px;
height: 500px;
scroll-behavior: inherit;
overflow: auto;
border: 2px solid black;
}
#inside{
height : 1000px;
}
The problem is that I see no difference. So what does it do?
Noticed it pop up in my Chrome Inspector as well, which lead me to this post...
What is the Scroll-Behavior?
Specifically referred to as CSSOM-View 'Scroll-Behavior' property, the css property was created to integrate more flexibility in CSS for DOM item scrolling. Most 'scroll-to' options that are built for websites are typically built on a JS library or plugin. Like others have mentioned, here is the release documentation - http://dev.w3.org/csswg/cssom-view/#scrolling
The current adopted scroll-behavior of the DOM is set to by anchor tags (example: Click Me). When this CSS property is fully adopted in all browsers, and correctly implemented (Check out this discussion : https://groups.google.com/forum/#!topic/mozilla.dev.platform/mrsNyaLj3Ig). You will be able to toggle the 'instant' anchor tag scroll to more of to a 'smooth' scroll.
The real question is when we this property be available in edge browsers? Currently, it is recognized by Firefox & Chrome, but the property is not 'Active' as far as research has gone.
nav{ float:left }
#scroll {
width: 350px;
height: 500px;
scroll-behavior: smooth;
overflow: scroll;
border: 2px solid black;
}
#inside1 {
height: 1000px;
background-color: blue;
}
#inside2 {
height: 1000px;
background-color: orange;
}
#inside3 {
height: 1000px;
background-color: red;
}
<nav>
#1
#2
#3
</nav>
<div id="scroll">
<div id="inside1"></div>
<div id="inside2"></div>
<div id="inside3"></div>
</div>
Check out the JSFiddle to see the implementation of how the instant scroll via anchor tags currently works through the DOM - http://jsfiddle.net/timcasonjr/5t0so7n7/3/
My CSS:
h1 {
background-color: #f7953d;
color: #FFF;
width: 100%;
padding: 6px 0 6px 10px;
margin-bottom: 10px;
}
My HTML
<h1>Hello World</h1>
The background color is always stretched to 100% of the screen. How do I make the background color stop after "World" in the h1 tag, and not go all the way to the end of the screen?
H1 is by default a block element and so will span the full width of its parent container you want to make it an inline element (much like a span) in order for it to only be as wide as its contents.
There are 2 possible solutions dependent on your compatability needs
display:inline;
will achieve the effect your after however it does mean that whatever follows your H1 could appear on the same line.
display:inline-block;
Has the effect your after while still forcing anything following it to appear below the H1 the only downside to this is it can throw up some issues in IE<8 see quirksmode for more details
You can do this by adding display: inline-block; to the CSS for your <h1>. This will make it use only as much width as its contents and still respect the margin and padding you give it.
I would suggest something like this:
HTML:
<h1>Hello World</h1>
<div class="clear"></div>
<p>Elements after unafected by float</p>
CSS:
h1 {
background-color: #f7953d;
color: #FFF;
padding: 6px 0 6px 10px;
margin-bottom: 10px;
float:left;
}
.clear {
clear:both;
}
This works consistently (unlike inline-block which isn't supported by all browsers).
An inline of the element is probably not what you want since you require padding.
Ok, I had a simple layout problem a week or two ago. Namely sections of a page needed a header:
+---------------------------------------------------------+
| Title Button |
+---------------------------------------------------------+
Pretty simple stuff. Thing is table hatred seems to have taken over in the Web world, which I was reminded of when I asked Why use definition lists (DL,DD,DT) tags for HTML forms instead of tables? Now the general topic of tables vs divs/CSS has previously been discussed, for example:
DIV vs Table; and
Tables instead of DIVs.
So this isn't intended to be a general discussion about CSS vs tables for layout. This is simply the solution to one problem. I tried various solutions to the above using CSS including:
Float right for the button or a div containing the button;
Position relative for the button; and
Position relative+absolute.
None of these solutions were satisfactory for different reasons. For example the relative positioning resulted in a z-index issue where my dropdown menu appeared under the content.
So I ended up going back to:
<style type="text/css">
.group-header { background-color: yellow; width: 100%; }
.group-header td { padding: 8px; }
.group-title { text-align: left; font-weight: bold; }
.group-buttons { text-align: right; }
</style>
<table class="group-header">
<tr>
<td class="group-title">Title</td>
<td class="group-buttons"><input type="button" name="Button"></td>
</tr>
</table>
And it works perfectly. It's simple, as backward compatibile as it gets (that'll work probably even on IE5) and it just works. No messing about with positioning or floats.
So can anyone do the equivalent without tables?
The requirements are:
Backwards compatible: to FF2 and IE6;
Reasonably consistent: across different browsers;
Vertically centered: the button and title are of different heights; and
Flexible: allow reasonably precise control over positioning (padding and/or margin) and styling.
On a side note, I came across a couple of interesting articles today:
Why CSS should not be used for layout; and
Tables vs CSS: CSS Trolls begone
EDIT: Let me elaborate on the float issue. This sort of works:
<html>
<head>
<title>Layout</title>
<style type="text/css">
.group-header, .group-content { width: 500px; margin: 0 auto; }
.group-header { border: 1px solid red; background: yellow; overflow: hidden; }
.group-content { border: 1px solid black; background: #DDD; }
.group-title { float: left; padding: 8px; }
.group-buttons { float: right; padding: 8px; }
</style>
</head>
<body>
<div class="group-header">
<div class="group-title">This is my title</div>
<div class="group-buttons"><input type="button" value="Collapse"></div>
</div>
<div class="group-content">
<p>And it works perfectly. It's simple, as backward compatibile as it gets (that'll work probably even on IE5) and it just works. No messing about with positioning or floats.</p>
<p>So can anyone do the equivalent without tables that is backwards compatible to at least FF2 and IE6?</p>
<p>On a side note, I came across a couple of interesting articles today:</p>
</div>
</body>
</html>
Thanks to Ant P for the overflow: hidden part (still don't get why though). Here's where the problem comes in. Say I want the title and button to be vertically centered. This is problematic because the elements are of different height. Compare this to:
<html>
<head>
<title>Layout</title>
<style type="text/css">
.group-header, .group-content { width: 500px; margin: 0 auto; }
.group-header { border: 1px solid red; background: yellow; overflow: hidden; }
.group-content { border: 1px solid black; background: #DDD; }
.group-header td { vertical-align: middle; }
.group-title { padding: 8px; }
.group-buttons { text-align: right; }
</style>
</head>
<body>
<table class="group-header">
<tr>
<td class="group-title">This is my title</td>
<td class="group-buttons"><input type="button" value="Collapse"></td>
</tr>
</table>
<div class="group-content">
<p>And it works perfectly. It's simple, as backward compatibile as it gets (that'll work probably even on IE5) and it just works. No messing about with positioning or floats.</p>
<p>So can anyone do the equivalent without tables that is backwards compatible to at least FF2 and IE6?</p>
<p>On a side note, I came across a couple of interesting articles today:</p>
</div>
</body>
</html>
which works perfectly.
There is nothing wrong with using the tools that are available to you to do the job quickly and correctly.
In this case a table worked perfectly.
I personally would have used a table for this.
I think nested tables should be avoided, things can get messy.
Just float left and right and set to clear both and you're done. No need for tables.
Edit: I know that I got a lot of upvotes for this, and I believed I was right. But there are cases where you simply need to have tables. You can try doing everything with CSS and it will work in modern browsers, but if you wish to support older ones... Not to repeat myself, here the related stack overflow thread and rant on my blog.
Edit2: Since older browsers are not that interesting anymore, I'm using Twitter bootstrap for new projects. It's great for most layout needs and does using CSS.
Float title left, float button right, and (here's the part I never knew until recently) - make the container of them both {overflow:hidden}.
That should avoid the z-index problem, anyway. If it doesn't work, and you really need the IE5 support, go ahead and use the table.
This is kind of a trick question: it looks terribly simple until you get to
Say I want the title and button to be vertically centered.
I want to state for the record that yes, vertical centring is difficult in CSS. When people post, and it seems endless on SO, "can you do X in CSS" the answer is almost always "yes" and their whinging seems unjustified. In this case, yes, that one particular thing is hard.
Someone should just edit the entire question down to "is vertical centring problematic in CSS?".
In pure CSS, a working answer will one day be to just use "display:table-cell". Unfortunately that doesn't work across current A-grade browsers, so for all that you might as well use a table if you just want to achieve the same result anyway. At least you'll be sure it works far enough into the past.
Honestly, just use a table if it's easier. It won't hurt.
If the semantics and accessibility of the table element really matter to you, there is a working draft for making your table non-semantic:
http://www.w3.org/TR/wai-aria/#presentation
I think this requires a special DTD beyond XHTML 1.1, which would just stir up the whole text/html vs application/xml debate, so let's not go there.
So, on to your unresolved CSS problem...
To vertically align two elements on their center: it can be done a few different ways, with some obtuse CSS hackery.
If you can fit within the following constraints, then there is a relatively simple way:
The height of the two elements is fixed.
The height of the container is fixed.
The elements will be narrow enough not to overlap (or can be set to a fixed width).
Then you can use absolute positioning with negative margins:
.group-header { height: 50px; position: relative; }
.group-title, .group-buttons { position: absolute; top: 50%; }
# Assuming the height of .group-title is a known 34px
.group-title { left: 0; margin-top: -17px; }
# Assuming the height of .group-buttons is a known 38px
.group-buttons { right: 0; margin-top: -19px; }
But this is pointless in most situations... If you already know the height of the elements, then you can just use floats and add enough margin to position them as needed.
Here is another method which uses the text baseline to vertically align the two columns as inline blocks. The drawback here is that you need to set fixed widths for the columns to fill out the width from the left edge. Because we need to keep the elements locked to a text baseline, we can't just use float:right for the second column. (Instead, we have to make the first column wide enough to push it over.)
<html>
<head>
<title>Layout</title>
<style type="text/css">
.group-header, .group-content { width: 500px; margin: 0 auto; }
.group-header { border: 1px solid red; background: yellow; }
.valign { display: inline-block; vertical-align: middle; }
.group-content { border: 1px solid black; background: #DDD; }
.group-title { padding: 8px; width: 384px; }
.group-buttons { padding: 8px; width: 84px; text-align: right; }
</style>
<!--[if lt IE 8]>
<style type="text/css">
.valign { display: inline; margin-top: -2px; padding-top: 1px; }
</style>
<![endif]-->
</head>
<body>
<div class="group-header">
<div class="valign">
<div class="group-title">This is my title.</div>
</div><!-- avoid whitespace between these! --><div class="valign">
<div class="group-buttons"><input type="button" value="Collapse"></div>
</div>
</div>
<div class="group-content">
<p>And it works perfectly, but mind the hacks.</p>
</div>
</body>
</html>
The HTML: We add .valign wrappers around each column. (Give them a more "semantic" name if it makes you happier.) These need to be kept without whitespace in between or else text spaces will push them apart. (I know it sucks, but that's what you get for being "pure" with the markup and separating it from the presentation layer... Ha!)
The CSS: We use vertical-align:middle to line up the blocks to the text baseline of the group-header element. The different heights of each block will stay vertically centered and push out the height of their container. The widths of the elements need to be calculated to fit the width. Here, they are 400 and 100, minus their horizontal padding.
The IE fixes: Internet Explorer only displays inline-block for natively-inline elements (e.g. span, not div). But, if we give the div hasLayout and then display it inline, it will behave just like inline-block. The margin adjustment is to fix a 1px gap at the top (try adding background colors to the .group-title to see).
I would recommend not using a table in this instance, because that is not tabular data; it's purely presentational to have the button located at the far right. This is what I'd do to duplicate your table structure (change to a different H# to suit where you are in your site's hierarchy):
<style>
.group-header { background: yellow; zoom: 1; padding: 8px; }
.group-header:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
/* set width appropriately to allow room for button */
.group-header h3 { float: left; width: 300px; }
/* set line-height or margins to align with h3 baseline or middle */
.group-header input { float: right; }
</style>
<div class="group-header">
<h3>This is my title</h3>
<input type="button" value="Collapse"/>
</div>
If you want true vertical alignment in the middle (ie, if the text wraps the button is still middle-aligned with respect to both lines of text), then you either need to do a table or work something with position: absolute and margins. You can add position: relative to your drop-down menu (or more likely its parent) in order to pull it into the same ordering level as the buttons, allowing you to bump it above them with z-index, if it comes to that.
Note that you don't need width: 100% on the div because it's a block-level element, and zoom: 1 makes the div behave like it has a clearfix in IE (other browsers pick up the actual clearfix). You also don't need all those extraneous classes if you're targeting things a bit more specifically, although you might need a wrapper div or span on the button to make positioning easier.
Do a double float in a div and use the clearfix. http://www.webtoolkit.info/css-clearfix.html Do you have any padding/margin restrictions?
<div class="clearfix">
<div style="float:left">Title</div>
<input type="button" value="Button" style="float:right" />
</div>
<div class="group-header">
<input type="button" name="Button" value="Button" style="float:right" />
<span>Title</span>
</div>
I've chose to use Flexbox, because it made things so much easier.
You basically need to go to the parent of the children you want to align and add display:box (prefixed of course). To make them sit in the sides, use justify-content. Space between is the right thing when you have elements which need to be aligned to the end, like in this case (see link)...
Then the vertical align issue. Because I made the parent of the two elements, you want to align a Flexbox. It's easy now to use align-items: center.
Then I added the styles you wanted before, removed the float from the title and button in the header and added a padding:
.group-header, .group-content {
width: 500px;
margin: 0 auto;
}
.group-header{
border: 1px solid red;
background: yellow;
overflow: hidden;
display: -webkit-box;
display: -moz-box;
display: box;
display: -webkit-flex;
display: -moz-flex;
display: -ms-flexbox;
display: flex;
-webkit-justify-content: space-between;
-moz-justify-content: space-between;
-ms-justify-content: space-between;
-o-justify-content: space-between;
justify-content: space-between;
webkit-align-items: center;
-moz-align-items: center;
-ms-align-items: center;
-o-align-items: center;
align-items: center;
padding: 8px 0;
}
.group-content{
border: 1px solid black;
background: #DDD;
}
.group-title {
padding-left: 8px;
}
.group-buttons {
padding-right: 8px
}
See Demo
I agree that one should really only use tables for tabular data, for the simple reason that tables don't show until they're finished loading (no matter how fast that is; it's slower that the CSS method). I do, however, feel that this is the simplest and most elegant solution:
<html>
<head>
<title>stack header</title>
<style type="text/css">
#stackheader {
background-color: #666;
color: #FFF;
width: 410px;
height: 50px;
}
#title {
color: #FFF;
float: left;
padding: 15px 0 0 15px;
}
#button {
color: #FFF;
float: right;
padding: 15px 15px 0 0;
}
</style>
</head>
<body>
<div id="stackheader">
<div id="title">Title</div>
<div id="button">Button</div>
</div>
</body>
</html>
The button function and any extra detail can be styled from this basic form. Apologies for the bad tags.