The Cache: Technology Expert's Forum
 
*
Welcome, Guest. Please login or register. September 21, 2019, 05:55:09 AM

Login with username, password and session length


Pages: [1] 2
  Print  
Author Topic: CSS Rounded Corner Boxes, Done The Right Way  (Read 14698 times)
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« on: June 12, 2008, 03:32:47 PM »

The reason for this article is that I’m doing a completely table-less layout for a client that needs every frigging WH SEO trick in the book (paranoid mortgage guy). There are several elements of the design that require a pliable rounded-rectangle box surrounding a changing block of text. So I started Googling and found lots of people that have done it, but in every case there was a trade off … it won’t work in this browser, it’s too complicated… only stretches horizontally or vertically, requires too much knowledge of the final size of the box, it didn’t work period… it needed to be written specifically for the content inside or it didn’t size right… you name it, always a problem.

So while talking to Nutballs about an unrelated challenge I asked him if he had any experience with such stuff and he had a bit, but had not done what I wanted – which was a 4-corner asymmetrical box in all CSS - the four corners would NOT be a simple rounding, they could conceivably be completely different. (Side note - my next site update for a client has a linen-rag looking backdrop for forms that must behave the same, but is anything but rounded corners). But he said one thing, (which I will demonstrate in a moment) that broke the whole thing wide open and helped me find a solution exactly the way I needed it. He said he'd seen CSS images overlap and stretch horizontally in all the browsers. That little fact was all I needed.

The common thread among all of the solutions that I found was that they tried to put all of the CSS into a single box – in other words, they tried to imagine a single rectangular DIV that managed to get a background image to show it’s 4 corners in the right position, then make it stretchy enough so that it would almost work right. (There was one solution from an Italian guy who called it "liquid corners" who got closer to the way that I did it here but still did not pull it off right).

(This is the problem with so called webmasters and CSS gurus – they see something that they want to get done but cannot think like a programmer, so the solutions involve the hackiest kludgy solutions around, rather than pulling back and reducing complexity, to get a stable, robust and reliable solution to a problem. I wish I had a nickel for every time I read "the math was really complex" or "this hack is required" or "this will only work when..." Grrrrr.)

But I digress. Most of you, probably just like me, if you've wanted a rounded-corner box, would create a 9-cell table: a TL corner, stretchy top, TR corner, stretchy left, body area, stretchy right, BL corner, stretchy bottom, and a BR corner. This works because we put stretchiness where we need it and lock in fixed graphics (the corners). As it happens, the CSS solution is pretty durn close.

A complete self-contained demo of this method can be found here:
   http://www.perkiset.org/demos/cssboxdemo.html
Stretch box around to see the CSS in action. View Source to see the whole thing


Functional Theory
There are lots of examples of a vertical stretchy box in CSS, and examples of a horizontal stretchy box. It’s the combination that makes things rough. So let’s put stretchiness only where we need it. Consider the box as 3 rows. All of these rows are horizontally stretchy, but the top and bottom are of a fixed height. The middle row is the only one that is really stretchy, but all that graphically needs to stretch is a “left bar” graphic and a “right bar” graphic – we don’t care about the corners because that’s taken care of by the top row and the bottom row.

The trick takes 3 images: a 4-corner image and a left and right bar image. The three I built for my client can be seen here:







All of them are really small PNGs, so download time is not an issue.
Here is the required CSS. I’ll outline what’s going on in a moment:

.plaqueTopLeft, .plaqueTopRight, .plaqueBottomLeft, .plaqueBottomRight { background-image: url("css3DBox.png"); }
.plaqueTopLeft { height: 16px; background-position: 0 0; }
.plaqueTopRight { height: 16px; background-position: 100% 0; margin-left: 20px; }
.plaqueBottomLeft { height: 28px; background-position: 0 100%; }
.plaqueBottomRight { height: 28px; background-position: 100% 100%; margin-left: 20px; }
.plaqueLeft { background-image: url("css3DLeft.png"); background-repeat: repeat-y; }
.plaqueRight { background-image: url("css3DRight.png"); background-position: 100% 0; background-repeat: repeat-y; margin-left: 20px; }
.plaqueCenter { margin-right: 30px; margin-left: 0px; }


Now here is an actual box on a web page:

<div class="plaqueTopLeft"><div class="plaqueTopRight"></div></div> <!-- the top row -->
<div class="plaqueLeft"><div class="plaqueRight"><div class="plaqueCenter">
   This is where all the content goes … it’s a normal div, you can put anything you want in here.
</div></div></div>
<div class="plaqueBottomLeft"><div class="plaqueBottomRight"> </div></div> <!-- the bottom row -->


How it works
Like many good HTML illusions, this only looks like one cohesive box. It's actually 3 rows of embedded divs, all constrained by an outer div to make them work together. (The outer div is implied here - it could be the page itself, or something like <div style="width: 50%"> it doesn't matter)

Let's take just the first row and the CSS that affects it and tear it apart (I've trimmed out stuff that doesn't apply):

.plaqueTopLeft, .plaqueTopRight { background-image: url("css3DBox.png"); }
.plaqueTopLeft { height: 16px; background-position: 0 0; }
.plaqueTopRight { height: 16px; background-position: 100% 0; margin-left: 20px; }

And the on page html...

<div class="plaqueTopLeft"><div class="plaqueTopRight"> </div></div>

Basically I have a div (plaqueTopLeft) that has a background image of css3DBox, and the background image should be placed at the 0, 0 position in the div. Note that I've only put the positioning here for clarity - this is the default and not required. Then inside of that div, I place another one (plaqueTopRight) with the same background image (this keeps download time really fast) however I tell it that I want the background image placed 100% right and 0 top. I also tell the plaqueTopRight div that I want it to have a margin of 20 px from the left of it's containing div... in this case, the the plaqueTopLeft div - so I get to see the rounded corner of the LEFT div and the rounded right corner of the RIGHT div completes the right side. If you try just that much HTML for yourself (scoff the images right from here) you'll see how the div is now horizontally stretchy. You'll also notice that if you create boxes larger than 800px this will fail because the images I made are only 800 px - so if you stretch too far apart you'll get white space. Fix this by simply making an image that's 2000 px across or something. Again, you'll only need to download it to the client once so it'll be pretty quick.

The second row uses the css descriptors for plaqueLeft and plaqueRight - which contain different images but do the exact same thing. Here's where the cool part comes in though - by repeating the Y of the background image, now the middle portion becomes VERTICALLY stretchy and baddabing, my div can now stretch horizontally or vertically and the graphics we have so far will adapt perfectly. Note that I also have plaqueCenter in the middle of the plaqueLeft and plaqueRight divs - this is to "reign in" my text on the right side.

The last row uses the css descriptors for the plaqueBottomLeft and plaqueBottomRight - again they do virtually the same thing as the plaqueTopLeft and plaqueTopRight except that this time we set the background position to be at the bottom.

Customizing for your own graphics
There are 4 magic numbers in the CSS above: 16px, 20px 28px and 30px. They all apply to this specific graphic. the tops are 16px tall because that makes the DIVs big enough to display the entire round corner. The bottoms are 28px high, because they must display the rounded corner AND the drop shadow. (Natch the asymmetry). The 20px margin is a somewhat arbitrary number, but it keeps the plaqueTopRight and BottomRight divs from "encroaching" on the left side divs. The margin 30px is what I need in the center div to keep my content out of the right-side 3d effect and drop shadow. So after having created your own graphic containers, you'll want to tweak these numbers so that you get the amount of padding and graphical effect your looking for.


Net-net
Rather than a complicated, hack-ridden and persnickety method for an asymmetrical rectangular container, this is a stable, standards compliant method that avoids the quirks that normally plague IE/FF/Safari browsers by way of interpretation irregularities. The only customization required for each box is to tailor the numbers to fit the graphical image, but since it's a custom image, that much is expected. Other than that, the CSS is replicable and easily reusable for any number of situations.

I tested the method in Safari, FF Mac, IE 6, IE 7 and FF for windows, it all works great. I don’t have IE 5, so if someone really wants to give that a shot that’d be great, but frankly, I’m rather unconcerned about that.

Enjoy!

/perk
« Last Edit: June 12, 2008, 05:15:15 PM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
dink
Expert
****
Offline Offline

Posts: 349


View Profile
« Reply #1 on: June 12, 2008, 11:07:31 PM »

Outstanding.  Outstanding.  Outstanding.

So simple.  No telling how many gurus have fought and lost the battle for roundies that stretch and render in all browsers.  Thousands perhaps.

Very well done, Perk.   Applause
Logged

[quote Nutballs]
the universe has a giant fist, and its got enough whoop ass for everyone.
[/quote]
DangerMouse
Expert
****
Offline Offline

Posts: 244



View Profile
« Reply #2 on: June 13, 2008, 02:58:06 AM »

 Smiley Great post thanks Perk, I've struggled finding a nice solution to creating rounded corners before now. Javascript solutions are nice, but slow in many cases. I despise CSS and all things design related so breaking it down like this is really handy!

DM
Logged
dimitry12
Rookie
**
Offline Offline

Posts: 27



View Profile
« Reply #3 on: June 13, 2008, 11:03:17 AM »

it's very close to:

Quote
<div class="up-right">
<div class="up-left">
<div class="down-right">
<div class="down-left">
text
</div>
</div>
</div>
</div>

and css:
Quote
.up-left{
 background: url(up-left.gif) top left no-repeat;
}

.up-right{
 background: url(up-right) top right no-repeat;
}

.down-left{
 background: url(down-left) bottom left no-repeat;
}

.down-right{
 background: url(down-right) bottom left no-repeat;
}

above may not work, just remembering and typing..

webrequest 2.1 is not working btw (pre-2.1 worked and worked nicer than bitchy curl  Vomit)..
Logged
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #4 on: June 13, 2008, 12:05:45 PM »

Tried that first D - the first and most important problem is that the backgrounds write all over each other. The last div (down-left in this case) would cover up all the other three. The tricky part is getting the divs to allow each other to show (their specific parts) of the image that make up the illusion of the box.

Height stuff is tougher to calculate than width stuff - so making the box stretch vertically in that scenario would be really tough - this is essentially what I saw an awful lot of when searching for an answer.

The trick above is to separate the top and bottom curves from the area that needs to be stretchy in the middle.

Thanks for the update on webRequest 2.1 ... NutBalls and I were working on some stuff and I don't think I ever wrapped it all up. You should stay with WR2 until I get around to sorting that out.
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
nutballs
Administrator
Lifer
*****
Offline Offline

Posts: 5627


Back in my day we had 9 planets


View Profile
« Reply #5 on: June 13, 2008, 12:29:26 PM »

ah... beautyous.

as usual,

Programmers FTW!

So my thought is if this can be made slightly more flexible.

what if the center background area of the whole rounded corner box, could be a seperate div, behind everything. This way you could use this to put fancy corners and edges on photos... The frame would be a PNG so you could alpha channel the middle area. Photo shows through inside but not outside. right now im on another project, but Im gonna try this an see. A little more complexity for a lot more control might be worth it. The other advantage would be to avoid weird texture seams, since you could put a full sized texture behind if you wanted.
Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #6 on: June 13, 2008, 01:05:34 PM »

Absolutely Nuts -

First, since the middle div is borderless and utterly tight against the outside, a "frame" around an image would be possible without the "behind" div. It would look like what you are asking for.

But to answer your question specifically, if you simply put the whole thing in another div with a background image, and then had transparencies in the framing graphics this would work perfectly. In fact, if you then put a thought-bubble type cartoon image at the top left of the image, for example, that would show on top of the background-div picture for a pretty cool display effect. And if I read you correctly, then you're not talking about simple frames, you're talking about rather ornate ones that would "impose themselves" over the image below... that'd be pretty damn cool actually.

And thanks again, BTW, for the gear-spinning kicker that made this work Wink
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
dimitry12
Rookie
**
Offline Offline

Posts: 27



View Profile
« Reply #7 on: June 13, 2008, 01:34:18 PM »

Tried that first D - the first and most important problem is that the backgrounds write all over each other. The last div (down-left in this case) would cover up all the other three. The tricky part is getting the divs to allow each other to show (their specific parts) of the image that make up the illusion of the box.

'padding' it?

http://browsehappy.com/people/sarah - "switched to firefox" -  box
Logged
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #8 on: June 13, 2008, 01:40:27 PM »

...what if the center background area of the whole rounded corner box, could be a seperate div, behind everything. This way you could use this to put fancy corners and edges on photos...

You intrigued me here so much I redid the demo to show that exact concept, as you outlined it. It is on the demo as well, here:

http://www.perkiset.org/demos/cssboxdemo.html
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #9 on: June 13, 2008, 01:43:06 PM »

'padding' it?

that's essentially how it's done D... but the challenge of the vertical resizing remains. So each row is 3 horizontally stretchy areas, but the top and bottom handle the graphics for the 4 corners because handling vertical stretchiness AND horizontal stretchiness within a single DIV will just give you the shits. Also, I got many different concepts to work in many different browser, but only this one worked in all of these: IE6, IE7, FF/Win, FF/Mac and Safari.
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #10 on: June 13, 2008, 02:05:36 PM »

http://browsehappy.com/people/sarah - "switched to firefox" -  box

They have a solution there and it's close to what I'm doing here... they use a mid-body method much like the Liquid Corners guy... I took their CSS and tried to put it to work and had a rough time getting it work in the same way, which is why I worked this exercise. I wanted a very stable and robust, replicable solution that is as independent of the content as possible. That was great to look at though
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
nutballs
Administrator
Lifer
*****
Offline Offline

Posts: 5627


Back in my day we had 9 planets


View Profile
« Reply #11 on: June 13, 2008, 03:10:49 PM »

very cool with the transparency as well.

I mocked up a quick example to exaggerate the usage.
rounded corners

The only quirkiness is that when you set the width of the constraining div and the height of the interior, you must subtract the corner values from the height. So in my example, my corners are 70x70, and there are 2 70's going from top to bottom. My image is 500 high, so 500-140 = height:360px; But that could be handled very easily, programmatically from the image size.

Other than that, its all easy as pie.

good work perk.
« Last Edit: July 09, 2008, 08:39:56 AM by nutballs » Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
dink
Expert
****
Offline Offline

Posts: 349


View Profile
« Reply #12 on: June 13, 2008, 03:14:22 PM »

Nice pic, NB's.  Cute.

Have you tried your idea as a full web page rather than just a snapshot border?
Logged

[quote Nutballs]
the universe has a giant fist, and its got enough whoop ass for everyone.
[/quote]
nutballs
Administrator
Lifer
*****
Offline Offline

Posts: 5627


Back in my day we had 9 planets


View Profile
« Reply #13 on: June 13, 2008, 03:24:18 PM »

thanks.

I imagine the principle is exactly the same, but the devil is in the details, meaning, it wont work. Though i guess this works because the photo is set as a background image. The content, if I was to type, without any margins set, it would just type in front of the corners, when we would want it to go behind actually.

Also because the top and bottom bars are separate divs, you would never be able to write into the space between the two horizontal corners. ie, topleft and topright.

something to think on a bit though... because i know where your evil mind is drifting off too....
Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
dink
Expert
****
Offline Offline

Posts: 349


View Profile
« Reply #14 on: June 13, 2008, 03:36:20 PM »

... because i know where your evil mind is drifting off too....

Moi?   Devilish
Logged

[quote Nutballs]
the universe has a giant fist, and its got enough whoop ass for everyone.
[/quote]
Pages: [1] 2
  Print  
 
Jump to:  

Perkiset's Place Home   Best of The Cache   phpMyIDE: MySQL Stored Procedures, Functions & Triggers
Politics @ Perkiset's   Pinkhat's Perspective   
cache
mart
coder
programmers
ajax
php
javascript
Powered by MySQL Powered by PHP Powered by SMF 1.1.2 | SMF © 2006-2007, Simple Machines LLC
Seo4Smf v0.2 © Webmaster's Talks


Valid XHTML 1.0! Valid CSS!