CSS Design: Creating Custom Corners & Borders
We’ve all heard the rap:
“Sites designed with CSS tend to be boxy and hard-edged. Where are the rounded corners?”
Answer: the rounded corners are right here. In this article, we’ll show how customized borders and corners can be applied to fully fluid and flexible layouts with dynamic content, using sound and semantically logical markup.
The markup
In the example markup below, XHTML line breaks have been inserted to pad out dummy paragraphs:
<h2>Article header</h2> <p> A few paragraphs of article text.<br /> A few paragraphs of article text. </p> <p> A few paragraphs of article text.<br /> A few paragraphs of article text. </p> <p> A paragraph containing author information </p>
The hooks
If we want full control of the layout, we need to make sure we have enough elements we can target with our CSS. Let’s call these elements “hooks.” Our markup needs just a few more.
First of all, let’s wrap the whole article in a containing div
, and then wrap each structural section in an appropriate element:
<div class="Article"> <h2>Article header</h2> <div class="ArticleBody"> <p> A few paragraphs of article text.<br /> A few paragraphs of article text. </p> <p> A few paragraphs of article text.<br /> A few paragraphs of article text. </p> </div> <div class="ArticleFooter"> <p> A paragraph containing author information </p> </div> </div>
If we examine the markup, we’ll see that we have given ourselves at least five hooks, which is all we need to place customized graphics in each of the four corners (and left side) of our article.
See Step 1 — primary markup.
The design
First let’s decide on some basic layout parameters. Our graphic designer gave us this mockup for reference:
“I want the borders and corners to look something like this,” he said. He also told us to be aware of the fact that all articles may have different widths and heights, and that he still wasn’t sure what kind of background he wanted the articles to have. In fact, he wasn't even sure those were the borders he wanted. “Could you leave that open, or make it so that it’s easy to change?” he asked.
THE PROCESS
We intend to keep the number of hooks as low as possible, so we’ll have to pay extra attention when we start to prepare the images for our solution, and make sure that the graphics we need are suitable to be hooked up to elements already present in our document.
We have a div
containing the whole article. That’ll do for our top left corner and top and left sides. Header elements are block-level by default, and we’ll take advantage of their behaviour: they extend to the full width of their parent element. So we’ll use the <h2>
element for our top right corner.
We’ll use our article-footer div
for the bottom left corner — and the contained paragraph for our bottom right corner.
Step 1.1 shows how we slice up the sketch.
Note: Obviously, you can use any element to hook graphics up with. Your document’s markup is unlikely to exactly match the structure used in our example. For all we know, you may only have a single paragraph of text to which you hope to apply customized corners and borders. You can easily do so.
As stated earlier, all you need is at least four structural elements. (Depending on the height of your element you may require five.) If necessary, these elements could be nonsemantic div
s, each with its ownclass
. Just remember that for a div
element to be rendered, it must contain content to manifest its presence. Also keep in mind that if your content lends itself to common structural elements such as headers, paragraphs, and so on, you can and should use those instead of relying on nonsemantic div
s.
The styles
To continue, let’s turn on element borders and set a relative width for thediv
that contains the whole article, to see how things behave:
div.Article { width:35%; border: 1px solid red; } div.Article h2 { border: 1px solid blue; } div.ArticleBody { border: 1px solid black; } div.ArticleFooter { border: 1px solid blue; } div.ArticleFooter p { border: 1px solid magenta; }
See Step 2 — basic element behaviour
Nothing really surprising here. We do, however, take notice of the gaps appearing before and after our div class="ArticleBody"
. Ignoring that problem for now, we’ll go on and write ourselves a style sheet:
body { background: #cbdea8; font: 0.7em/1.5 Geneva, Arial, Helvetica, sans-serif; } div.Article { background: url(images/custom_corners_topleft.gif) top left no-repeat; width:35%; } div.Article h2 { background: url(images/custom_corners_topright.gif) top right no-repeat; } div.ArticleBody { background: url(images/custom_corners_rightborder.gif) top right repeat-y; } div.ArticleFooter { background: url(images/custom_corners_bottomleft.gif) bottom left no-repeat; } div.ArticleFooter p { background: url(images/custom_corners_bottomright.gif) bottom right no-repeat; }
See Step 3 — first attempt
Not bad at all! Actually better than we expected. Obviously we need to add some padding to our respective elements to make the layout look better — and then there are those pesky gaps to fix. The gaps are caused by the carriage returns inserted by our paragraph (block) elements. We could avoid using paragraph elements altogether and thereby bypass the problem, but — for reasons well-known to ALA readers — we prefer to keep our markup structurally clean and logical. It isn’t our data’s fault that we are lazy stylers.
In our first pass, we assumed that a carriage return must equal 1.5em
, as that was the value we specified for our line-height. Therefore our first attempt was to add a margin-top:-1.5em
to our ArticleBody
andArticleFooter
. It worked perfectly in most standards-compatible browsers — all except the ones used by the 94% of internet users on this planet (nonames, please).
After testing, trial, error, rinse, and repeat we find that we must use at least a margin-top:-2em
to be sure that the elements touch and the gap closes:
div.Article { background: url(images/custom_corners_topleft.gif) top left no-repeat; width:35%; } div.Article h2 { background: url(images/custom_corners_topright.gif) top right no-repeat; font-size:1.3em; padding:15px; margin:0; } div.ArticleBody { background: url(images/custom_corners_rightborder.gif) top right repeat-y; margin:0; margin-top:-2em; padding:15px; } div.ArticleFooter { background: url(images/custom_corners_bottomleft.gif) bottom left no-repeat; } div.ArticleFooter p { background: url(images/custom_corners_bottomright.gif) bottom right no-repeat; display:block; padding:15px; margin:-2em 0 0 0; }
Step 4 — looks like we’re finally there!
Backward compatibility?
If you’ve been viewing this example in Netscape 4.x, you’ve probably noticed that the page shows up blank. We’ve found no way to get this technique to work acceptably in NS 4.x, so instead we’re going to hide the styles that the browser in question cannot render properly. NS 4.x does not understand style
tags with media="all"
specified and we’ve taken advantage of that in the example that follows. We’ve made two style tags, one with styles we want all browsers to render, and another we intend to hide from NS 4.x. Even though it breaks our heart to do so, we’ve also changed our font size specification from em
s to px
s. You wanted backward compatibility — you’ve got it.
Step 5 — graceful degradation in NS 4.x
The real world
“Yeah — but we want to see real-world applications, mate,” you say. We anticipated that and provided an example of the technique applied in a more advanced context. We borrowed an already thoroughly tested layout fromAlex Robinson, and applied our styles to it — and we’re glad we did!
Our first attempt unleashed a cavalcade of calamities in IE6/Win, triggering bugs affecting z-index
stacking level of our elements. Entire elements disappeared; margins acted like children kept up long past their bedtime. It was a mess. Then we learned that a simple position:relative
and a well positioned <br />
could fix everything. View the source in Step 6 for further investigation.
Step 6 — our attempt at applying our technique to a full-fledged layout with headers, columns, and footers
Limitations
If you have been paying attention, you probably realize this example only plays well with surrounding, solid-color backgrounds. With this method we need to cover the graphics from the top left corner with the graphics in the top right corner. If we made the top right corner graphic transparent, the top left graphic beneath it would show. Same goes for the bottom. And that is indeed a limitation. Perhaps in a Part II edition of this article we will show how to work with gradient backgrounds.
Meanwhile, this article demonstrates a generic method, with backward compatibilty and sound markup in mind, and it is our sincere hope that this will inspire a lot of offspring and ideas — perhaps even some that avoid the need to work with solid background colors.
Acknowledgements
Brian Alvey for discussions, insisting on graceful degradation and real world examples, and David Schontzler for helping a Danish dude write technical text in English.
Editor’s note
While we were preparing this ALA issue for publication, designer Ryan Thrash came up with a nearly identical approach to the problem of creatingrounded CSS boxes based on semantically correct markup. Thrash and Madsen came up with their approaches independently of each other; both authors acknowledge the influence of Douglas Bowman’s previous ALA articles, Sliding Doors of CSS (20 October 2003) and Sliding Doors of CSS II (30 October 2003).
Independently of all that, ALA systems designer Brian Alvey previously crafted a different approach to rounded corners, which may be seen atWeblogs, Inc. It’s all good. — Ed.
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单
· C# 13 中的新增功能实操
· Supergateway:MCP服务器的远程调试与集成工具
· Vue3封装支持Base64导出的电子签名组件