CSS Best Practices for decoupled modules - css

The answer to this question is not pointing out some css selector or property that I am unaware of. It is also not throwing together some random css that makes this specific case work. Off the top of my head I can think of several ways to make this specific example work. I'm sure there are hundreds more.
What are the best practices for creating CSS such that various design elements are decoupled?
Explanation of what I mean:
I am a computer programmer with an ok design sense. When writing good code I look to create classes/objects that are decoupled, meaning there are not strange and unexpected interactions between them. I can mix and match my classes/objects freely and the results work well and are what you would expect. All my attempts to learn/create CSS best practises don't work out this well. I've been a .NET web developer for 10+ years now. For a long time I believed in semantic CSS. I loved csszengarden.com. I've tried to learn OOCSS and SMACSS. Despite all that I can't get my CSS to work the way I can get my code to work. I search online for CSS best practices and find things like naming, formatting and a few tips and tricks. Never a deep understanding of how to create decoupled CSS. Perhaps it is just impossible. I don't feel like it should be. I feel like it should be possible to create a design language of reusable elements that can be composed.
Since all that is very abstract and it is hard to discuss without an example. Here is an example of the challenges I run into. This is based on a situation involving bootstrap, but I have simplified the styles. So please understand the styles are the way they are because that is what makes sense for the rest of the site and this example isn't about some trivial change that makes it work in this exact case.
Example:
Code for this is on jsbin.
I have a panel module with header and content. Typically the header contains an h2 and one or more button actions:
Note, the equal padding around the header and the actions float right. This design is responsive and when the panel is narrow, the actions must drop below the title. Though there is actually an issue when that happens in that there is no space between the title and button.
But really, the panel is a module that can have anything it its header. This should follow the OOCSS principle of "separation of containers and contents". So it shouldn't really matter what we put in the panel header. We want it to work well.
Now on a particular page it make sense to put a select list in the panel header. Like with Bootstrap there are many styles that pertain to forms, so we use these styles here as well. The result looks something like:
Notice that because the form-group (per Bootstrap) has a bottom margin there is now double the space at the bottom of the header (the bottom margin provides correct spacing in forms with multiple form groups). I am in agreement with our designer that the double space is wrong, it should be an equal amount of space as the top (like in the simpler example). I found a good article on ways to try to deal with this. However, the "best" option at the end (uses *:last-child) which is the one I like doesn't work here because the form is not the last element in the container because the action button must float below the select list when the window is small. Also, I feel like situations like that can always arise. Note that in this case when the window is small and the button floats below the select, the spacing is good because the margin on the form-group provides spacing between them.
Additionally, the designer says the button should be vertically aligned with the select (looks better with bootstrap because the inputs are the same height). It feels like there is no way to accomplish that which isn't very specific to the particular combination of elements here or to the particular page this appears on. That is, I can't imagine a generic best practice for making things like that line up right.
CSS for the above is too long to include in this already long question, but again check out the jsbin.
Restatement of Question:
Again, I am not looking for specific CSS that will fix this particular example. I want to know what best practices will allow me to create CSS for decoupled design elements that can be freely combined without constantly running into issues like the above.

On composability in CSS
Position, dimensions of children should be responsibility of parents
What are the best practices for creating CSS such that various design
elements are decoupled?
I have given this subject considerable thought and I was glad to have been sent a link to your article "CSS is Not Composable" by a colleague, which is how I found this question.
Because CSS intrinsically lends itself to creating selectors in a global space, separating decoupled modules into namespaces is a wise best practice.
You may optionally define base styles for a generic component class at the global level, but rely on namespace classes and/or IDs to apply positional and dimensional styles to the components based on where they are included.
Do not apply positional or dimensional styles directly to any component container. All other styles are defined by the component within its namespace.
In other words, the position and dimensions of a child component should be the responsibility of the parent container.
Correct:
/* A component namespace */
.my-component-A {
padding: 10px;
background-color: White;
}
/* A component styles its children as necessary */
.my-component-A > p {
margin: 0 0 1em 0;
}
/* Position & dimension applied by parent (Page A) within its namespace */
.my-page-A .my-component-A {
float: left;
margin: 0 10px 0 0;
}
/* Position & dimension applied by parent (Page B) within its namespace */
.my-page-B .my-component-A {
float: right;
margin: 0 0 0 10px;
}
/* Position & dimension applied by parent (Component B) within its namespace */
.my-component-B .my-component-A {
margin: 10px;
}
Incorrect:
/* Position & dimension applied by component within its own namespace */
.my-component-A {
float: left;
margin: 0 10px 0 0;
padding: 10px;
background-color: White;
}
/* Position & dimension now have to be overridden by parent */
.my-component-B .my-component-A {
float: none;
margin: 10px;
}
By using the parent component or page namespace to apply position and dimension to child components, you create a system of fully composable decoupled modules. And because a component will never change its own size or position, the developer who maintains the parent component or page has assurance that they are in control of the layout of its children.
If you are consistent and intentional, each component is capable of being placed into any other component. And because it doesn't define its own size or position, it flows into the parent container with its browser default positional and dimensional styles or with the styles provided by your global reset.
You, as the developer who maintains a page or parent component, have complete freedom to modify the layout of everything under that namespace without needing to apply overrides. And if your team is on board with this best practice, you don't need to worry that namespaced style changes made to a child component maintained by someone else will break the layout of the page or parent component you maintain.
Every component is position- and dimension-ignorant, relying entirely on its parent component or page to define its placement and size as necessary.
In your example, we can apply this principal to create a form group component that can be placed on a page and into other components at various depths while relinquishing control over layout to the page or parent component.
/* Component Base / generic reset */
.component {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* Use generic page and component class to target all child components at once */
.pagewrapper > .component {
margin: 20px;
}
/* Component: Panel */
.component.panel {
/* No positional styles defined on component container */
border: 1px solid Black;
}
.component.panel .panel-header {
/* `display: table` is a great legacy & cross-browser solution for vertical alignment */
display: table;
position: relative;
overflow: auto;
border-bottom: 1px solid Gray;
}
.component.panel .panel-header > * {
/* set all immediate children as table-cells to get vertical-alignment */
display: table-cell;
padding: 10px;
table-layout: auto;
border-collapse: collapse;
vertical-align: middle;
}
.component.panel .panel-header > .actions {
width: 1%;
}
.component.panel .panel-header h2 {
margin: 0;
font-size: 25px;
}
.component.panel .panel-content {
/* Exclude bottom padding and apply margin-bottom to immediate children instead */
padding: 10px 10px 0;
}
.component.panel .panel-content > * {
/* All immediate children of the container get a bottom margin */
margin: 0 0 10px;
}
/* Component: Form Group */
.component.form-group {
/* No positional styles defined on component container */
padding: 10px;
background-color: Beige;
}
.component.form-group label {
display: block;
}
/* Component position and dimension are namespaced to the parent */
.pagewrapper.home > .component.form-group {
/* Use child selector to limit scope of namespaced components where a component may exist multiple times as descendants of the same ancestor. */
/* You may override any other styles such as background-colors */
background-color: Lavender;
}
.component.panel .panel-header .component.form-group {
/* Positional style is always applied in the context of a parent container… */
margin: -10px;
}
.component.panel .panel-content .component.form-group {
/* …because it may need different positioning even within the same parent component. */
margin: 0 -10px;
}
.component.panel .panel-content .component.form-group:first-child {
/* Strategically use pseudo-class selectors… */
margin: -10px -10px 0;
}
.component.panel .panel-content .component.form-group + * {
/* …and sibling selectors (and other selectors as warranted). */
margin-top: 10px;
}
<main class="pagewrapper home" id="my-page-A">
<!-- Position and dimension defined by page…
`.pagewrapper > .component` -->
<section class="component panel" id="my-panel-A">
<div class="panel-header">
<h2>Title</h2>
<div class="actions">
<button>Add</button>
</div>
</div>
<div class="panel-content">
<p>Content</p>
</div>
</section>
<section class="component panel" id="my-panel-B">
<div class="panel-header">
<!-- Position and dimension defined by parent component…
`.component.panel .panel-header .component.form-group` -->
<div class="component form-group" id="my-form-group-A">
<label>A Label</label>
<select>
<option>Something</option>
</select>
</div>
<div class="actions">
<button>Add</button>
</div>
</div>
<div class="panel-content">
<p>Content</p>
<p>More content</p>
</div>
</section>
<section class="component panel" id="my-panel-C">
<div class="panel-header">
<h2>Title</h2>
<div class="actions">
<button>Add</button>
</div>
</div>
<div class="panel-content">
<p>Content</p>
<!-- Position and dimension defined by parent component…
`.component.panel .panel-content .component.form-group` -->
<div class="component form-group" id="my-form-group-B">
<label>A Label</label>
<select>
<option>Something</option>
</select>
</div>
<p>More content</p>
</div>
</section>
<!-- Position and dimension defined by namespaced page…
`.pagewrapper.home > .component.form-group` -->
<div class="component form-group" id="my-form-group-C">
<label>A Label</label>
<select>
<option>Something</option>
</select>
</div>
</main>

CSS is not meant to be separate. It is intended to have a parent to child cascading effect and can be quite powerful, reliable and resilient when applied well. OOCSS is close to what you want but not quite. With OOCSS the intention is to put common attributes in a single class that can be reused for many instances.
I think what you may want to do is look into Web Components and the use of Shadow DOM. It allows you to create your widgets so that they have their own styling separate from the main page DOM and can reduce the chance for unwanted styling even further.
EDITED: I know you said you are looking for best practices and not solutions. However, I felt I should provide some possible code samples as possible "best practice" solutions to your posted situation. For more control you you should utilize more specific css selectors as they will be given the higher importance when rendering. As a "best practice" for greatest control you should use containers with unique ID's that you can use to target sections of your html with greater specificity (ie. #mainContent, #sideBar, #myWidgetName, etc.). Then you can pair these with various CSS3 Selectors to increase the specificity and achieve greater control.
TLDR: General CSS Best Practices
Start with Base styles (OOCSS is good for this)
Add unique ID's to your important container elements
Use Container ID's, classes, CSS3 selectors, etc. to specifically
target elements inside those containers and override base styles as
needed
Also keep in mind that where you place your rules are important (top of stylesheet, bottom of stylesheet, inline, etc.)
/* ----- YOUR ORIGINAL STYLES -----*/
/* General form styles */
.form-group {/* like bootstrap, need space between form inputs */margin-bottom: 10px;}
.form-group label {display: block;}
/* Panel styles */
.panel {border: 1px solid black; background-color: white; margin: 20px;}
.panel-header {padding: 10px; border-bottom: 1px solid grey;}
.panel-header h2 {font-size: 25px; margin: 0px; display: block; float: left;}
.panel-header .form-group {float: left;}
.panel-header .actions {float: right; margin-top: 2px; /* nudge down to try and line up with title */}
.panel-content {padding: 10px;}
/* generic clear fix */
.clearfix:after {content: ""; display: table; clear: both;}
/* ----- SUGGESTED SOLUTION STYLES -----*/
.panel-header {position:relative;/* will assist with button alignment */}
.panel-header > *:nth-child(n) {
margin-bottom: 0;/* zero out the bottom margin of all direct children of ".panel-header" */
}
#media (min-width: 768px) {
.panel-header .actions { /* now that the bottom margins are set this will position the button to be aligned to the bottom of the container */
bottom: 10px;/*matches .panel-header margin*/
float: none;
position: absolute;
right: 10px;/*matches .panel-header margin*/
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div class="panel">
<div class="panel-header clearfix">
<h2>Title</h2>
<div class="actions">
<button>Add</button>
</div>
</div>
<div class="panel-content">
Content
</div>
</div>
<div class="panel">
<div class="panel-header clearfix">
<div class="form-group">
<label>A Label</label>
<select>
<option>Something</option>
</select>
</div>
<div class="actions">
<button>Add</button>
</div>
</div>
<div class="panel-content">
Content
</div>
</div>
</body>
</html>

Related

Changing CSS Property From an Array using JS

I am currently building a todo app, and from react, I am using CSS to custom my todo items' margin!
The problem is, I only needed the first element to have a margin-top of 110px. Here's what it'll look like when I apply it to every item - link
It's that the todolist items are too separated!
But if I removed the margin of 110px, the item is behind the textbox!
link
Is there a way to change the property of first item? I can delete the margin-top: 110px from the css file, and change the 1st item using JS. My planned function -
function addTodo() {
setList([...list, value]);
const firstItem = list.findIndex(0);
}
Thanks!
:first-of-type selector in CSS allows you to target the first occurence of an element within its container. Also, another option might be to select first child of the element, you can use :first-child pseudo-class.
There are several possibilities to solve this problem. I think the simplest one is to just build a container that contains all list items, and set it's padding-top or margin-top to 110px. The result could look like this:
.frame {
margin-left: auto;
margin-right: auto;
padding: 10px;
width: 200px;
border: 1px solid #000;
text-align: center;
}
.control-button {
position: absolute;
}
/* this is the container that holds all your items */
.items-container {
margin-top: 40px; /* in your case, it should be 110px */
}
.item {
margin-top: 10px;
border: 1px solid #000;
}
<html>
<body>
<div class="frame">
<div class="control-button">
<u>add item</u>
</div>
<!-- this is the important part, the container with the items -->
<div class="items-container">
<div class="item">
This is an item.
</div>
<div class="item">
This is another item.
</div>
</div>
</div>
</body>
</html>
I think this solution is the most simple and flexible one. You can easily add left, right or bottom margins too and you don't have to worry about which items it affects.
The simplest solution you can go with is using the :nth-child(n) pseudo class in CSS or :first-of-type.
Try this code:
.item:nth-child(1) {
margin-top: 110px;
}

CSS specifity / inheritance issue

I'm attaching a 3rd party component to a div element (container). This div element is inside a from and the form has the class cssform. my main css sheet I use contains the definition:
.cssform div {
max-width: 680px;
clear: left;
margin: 0;
padding: 5px 0 8px 0;
padding-left: 155px;
}
My container is now affected by this css which makes the 3rd party component visual unusable.
How can I "overwrite" or "reset" this above css so that it is not applied in any children of my container especially taking into account 3rd party component itself creates div elements below mine also affected from this forms css
EDIT:
The structure is
<form class="cssform">
<section>
<div>
<label></label><input>
</div>
<div id="container"></div>
<div>
<label></label><input>
</div>
<section>
</form>
I fixed this by simply giving all the divs except the container an addtional css class and using that to assign the forms style. that way my container is not affected. I'm not adding this as an answer because it's technical not an answer to my question but a work-around.
If you your div element is, lets say, the third child of its parent container, you can use the pseudo-class :not with :nth-child(3):
.cssform div:not(:nth-child(3)) {
max-width: 680px;
clear: left;
margin: 0;
padding: 5px 0 8px 0;
padding-left: 155px;
}
You may have to edit the selector depending on your entire block of code. But I believe the CSS selector you are looking for is :not(:nth-child(n)).
If you are trying to style only one particular div, the solution depends on which exact HTML structure you have. For example, if the form looks like
<form class="cssform">
<section>
<div>
<div> this one!
<div> but not this one! </div>
</div>
<div> nor this one! </div>
<div>
<section>
</form>
then the css needs to be like this:
.cssform > section > div > div:first-child {...}
Hope this helps.

Style a class only inside a table

I'm using a CMS with predefined classes (cbFormFieldCell).
So I can't change some class elements because they are used at some other parts of the website. If I change the format for every element of that class the website is broken.
I want to change the style of the class "cbFormFieldCell" only inside a <table class="tabelle">. Outside the table the other elements may not be changed.
.cbFormFieldCell { min-width: 300px; max-width: 300px; overflow: hidden;}
That works for every class of the website. But some objects are broken.
Is it possible to do something like that:
Change only predefined class="cbFormFieldCell" elements in table class="tabelle"?
e.g.
.tabelle.cbFormFieldCell
{ min-width: 300px; max-width: 300px; overflow: hidden; }
Can anyone help?
The 'space' between your CSS classes are used to target different elements. Below you will find an example what happens when you combine classes without or with spaces.
Hopefully this help you to understand how to target your element.
.parent-1 .child {
color: green;
}
.parent-2.child {
color: red;
}
/* addition styling */
p {
padding: 20px;
background-color: #eff0f1;
border-radius: 10px;
}
<!-- Without container -->
<p class="child">No CSS rules are applied here.</p>
<!-- With containers -->
<div class="parent-1">
<p class="child">This will be targeted: green</p>
</div>
<div class="parent-2">
<p class="child">No CSS rules are applied here.</p>
</div>
<div class="parent-2 child">
<p class="child">This will be targeted: red</p>
</div>
You can use css !important like this
.cbFormFieldCell { min-width: 300px !important; max-width: 300px !important; overflow: hidden !important;}
"!important" makes css attribute to be first-level
You are concatenating the classes by writing them with no space, which basically means
.tabelle.cbFormFieldCell will apply to an element that has BOTH those classes.
In order to target .cbFormFieldCell inside of .tabelle add a space between them like this .tabelle .cbFormFieldCell.
Or if it's a direct child of .tabelle, you can use the descendant selector like this .tabelle > .cbFormFieldCell
Thank you everyone!
I actually had to remove the space, use important and additionally use another default class.
.cbFormTableEvenRow .cbFormFieldCell
{ min-width: 100px !important; max-width: 100px !important; width: 100px !important; overflow: hidden !important; }

Twitter Bootstrap - borders

I just started using Twitter Bootstrap, and I have a question about how to best add a border to a parent element?
for instance, if I have
<div class="main-area span12">
<div class="row">
<div class="span9">
//Maybe some description text
</div>
<div class="span3">
//Maybe a button or something
</div>
</div>
</div>
If I apply a border like so:
.main-area {
border: 1px solid #ccc;
}
The grid system will break and kick span3 down to the next row because of the added width of the border......Is there a good way to be able to add things like borders or padding to the parent <div>s like this?
If you look at Twitter's own container-app.html demo on GitHub, you'll get some ideas on using borders with their grid.
For example, here's the extracted part of the building blocks to their 940-pixel wide 16-column grid system:
.row {
zoom: 1;
margin-left: -20px;
}
.row > [class*="span"] {
display: inline;
float: left;
margin-left: 20px;
}
.span4 {
width: 220px;
}
To allow for borders on specific elements, they added embedded CSS to the page that reduces matching classes by enough amount to account for the border(s).
For example, to allow for the left border on the sidebar, they added this CSS in the <head> after the the main <link href="../bootstrap.css" rel="stylesheet">.
.content .span4 {
margin-left: 0;
padding-left: 19px;
border-left: 1px solid #eee;
}
You'll see they've reduced padding-left by 1px to allow for the addition of the new left border. Since this rule appears later in the source order, it overrides any previous or external declarations.
I'd argue this isn't exactly the most robust or elegant approach, but it illustrates the most basic example.
Another solution I ran across tonight, which worked for my needs, was to add box-sizing attributes:
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
These attributes force the border to be part of the box model's width and height and correct the issue as well.
According to caniuse.com » box-sizing, box-sizing is supported in IE8+.
If you're using LESS or Sass there is a Bootstrap mixin for this.
LESS:
.box-sizing(border-box);
Sass:
#include box-sizing(border-box);

What methods of ‘clearfix’ can I use?

I have the age-old problem of a div wrapping a two-column layout. My sidebar is floated, so my container div fails to wrap the content and sidebar.
<div id="container">
<div id="content"></div>
<div id="sidebar"></div>
</div>
There seem to be numerous methods of fixing the clear bug in Firefox:
<br clear="all"/>
overflow:auto
overflow:hidden
In my situation, the only one that seems to work correctly is the <br clear="all"/> solution, which is a little bit scruffy. overflow:auto gives me nasty scrollbars, and overflow:hidden must surely have side effects.
Also, IE7 apparently shouldn't suffer from this problem due to its incorrect behaviour, but in my situation it's suffering the same as Firefox.
Which method currently available to us is the most robust?
Depending upon the design being produced, each of the below clearfix CSS solutions has its own benefits.
The clearfix does have useful applications but it has also been used as a hack. Before you use a clearfix perhaps these modern css solutions can be useful:
css flexbox
css grid
Modern Clearfix Solutions
Container with overflow: auto;
The simplest way to clear floated elements is using the style overflow: auto on the containing element. This solution works in every modern browsers.
<div style="overflow: auto;">
<img
style="float: right;"
src="path/to/floated-element.png"
width="500"
height="500"
>
<p>Your content here…</p>
</div>
One downside, using certain combinations of margin and padding on the external element can cause scrollbars to appear but this can be solved by placing the margin and padding on another parent containing element.
Using ‘overflow: hidden’ is also a clearfix solution, but will not have scrollbars, however using hidden will crop any content positioned outside of the containing element.
Note: The floated element is an img tag in this example, but could be any html element.
Clearfix Reloaded
Thierry Koblentz on CSSMojo wrote: The very latest clearfix reloaded. He noted that by dropping support for oldIE, the solution can be simplified to one css statement. Additionally, using display: block (instead of display: table) allows margins to collapse properly when elements with clearfix are siblings.
.container::after {
content: "";
display: block;
clear: both;
}
This is the most modern version of the clearfix.
⋮
⋮
Older Clearfix Solutions
The below solutions are not necessary for modern browsers, but may be useful for targeting older browsers.
Note that these solutions rely upon browser bugs and therefore should be used only if none of the above solutions work for you.
They are listed roughly in chronological order.
"Beat That ClearFix", a clearfix for modern browsers
Thierry Koblentz' of CSS Mojo has pointed out that when targeting modern browsers, we can now drop the zoom and ::before property/values and simply use:
.container::after {
content: "";
display: table;
clear: both;
}
This solution does not support for IE 6/7 …on purpose!
Thierry also offers: "A word of caution: if you start a new project from scratch, go for it, but don’t swap this technique with the one you have now, because even though you do not support oldIE, your existing rules prevent collapsing margins."
Micro Clearfix
The most recent and globally adopted clearfix solution, the Micro Clearfix by Nicolas Gallagher.
Known support: Firefox 3.5+, Safari 4+, Chrome, Opera 9+, IE 6+
.container::before, .container::after {
content: "";
display: table;
}
.container::after {
clear: both;
}
.container {
zoom: 1;
}
Overflow Property
This basic method is preferred for the usual case, when positioned content will not show outside the bounds of the container.
http://www.quirksmode.org/css/clearing.html
- explains how to resolve common issues related to this technique, namely, setting width: 100% on the container.
.container {
overflow: hidden;
display: inline-block;
display: block;
}
Rather than using the display property to set "hasLayout" for IE, other properties can be used for triggering "hasLayout" for an element.
.container {
overflow: hidden;
zoom: 1;
display: block;
}
Another way to clear floats using the overflow property is to use the underscore hack. IE will apply the values prefixed with the underscore, other browsers will not. The zoom property triggers hasLayout in IE:
.container {
overflow: hidden;
_overflow: visible; /* for IE */
_zoom: 1; /* for IE */
}
While this works... it is not ideal to use hacks.
PIE: Easy Clearing Method
This older "Easy Clearing" method has the advantage of allowing positioned elements to hang outside the bounds of the container, at the expense of more tricky CSS.
This solution is quite old, but you can learn all about Easy Clearing on Position Is Everything: http://www.positioniseverything.net/easyclearing.html
Element using "clear" property
The quick and dirty solution (with some drawbacks) for when you’re quickly slapping something together:
<br style="clear: both" /> <!-- So dirty! -->
Drawbacks
It's not responsive and thus may not provide the desired effect if layout styles change based upon media queries. A solution in pure CSS is more ideal.
It adds html markup without necessarily adding any semantic value.
It requires a inline definition and solution for each instance rather than a class reference to a single solution of a “clearfix” in the css and class references to it in the html.
It makes code difficult to work with for others as they may have to write more hacks to work around it.
In the future when you need/want to use another clearfix solution, you won't have to go back and remove every <br style="clear: both" /> tag littered around the markup.
What problems are we trying to solve?
There are two important considerations when floating stuff:
Containing descendant floats. This means that the element in question makes itself tall enough to wrap all floating descendants. (They don't hang outside.)
Insulating descendants from outside floats. This means that descendants inside of an element should be able to use clear: both and have it not interact with floats outside the element.
Block formatting contexts
There's only one way to do both of these. And that is to establish a new block formatting context. Elements that establish a block formatting context are an insulated rectangle in which floats interact with each other. A block formatting context will always be tall enough to visually wrap its floating descendants, and no floats outside of a block formatting context may interact with elements inside. This two-way insulation is exactly what you want. In IE, this same concept is called hasLayout, which can be set via zoom: 1.
There are several ways to establish a block formatting context, but the solution I recommend is display: inline-block with width: 100%. (Of course, there are the usual caveats with using width: 100%, so use box-sizing: border-box or put padding, margin, and border on a different element.)
The most robust solution
Probably the most common application of floats is the two-column layout. (Can be extended to three columns.)
First the markup structure.
<div class="container">
<div class="sidebar">
sidebar<br/>sidebar<br/>sidebar
</div>
<div class="main">
<div class="main-content">
main content
<span style="clear: both">
main content that uses <code>clear: both</code>
</span>
</div>
</div>
</div>
And now the CSS.
/* Should contain all floated and non-floated content, so it needs to
* establish a new block formatting context without using overflow: hidden.
*/
.container {
display: inline-block;
width: 100%;
zoom: 1; /* new block formatting context via hasLayout for IE 6/7 */
}
/* Fixed-width floated sidebar. */
.sidebar {
float: left;
width: 160px;
}
/* Needs to make space for the sidebar. */
.main {
margin-left: 160px;
}
/* Establishes a new block formatting context to insulate descendants from
* the floating sidebar. */
.main-content {
display: inline-block;
width: 100%;
zoom: 1; /* new block formatting context via hasLayout for IE 6/7 */
}
Try it yourself
Go to JS Bin to play around with the code and see how this solution is built from the ground up.
Traditional clearfix methods considered harmful
The problem with the traditional clearfix solutions is that they use two different rendering concepts to achieve the same goal for IE and everyone else. In IE they use hasLayout to establish a new block formatting context, but for everyone else they use generated boxes (:after) with clear: both, which does not establish a new block formatting context. This means things won't behave the same in all situations. For an explanation of why this is bad, see Everything you Know about Clearfix is Wrong.
The newest standard, as used by Inuit.css and Bourbon - two very widely used and well-maintained CSS/Sass frameworks:
.btcf:after {
content:"";
display:block;
clear:both;
}
Notes
Keep in mind that clearfixes are essentially a hack for what flexbox layouts can now provide in a much easier and smarter way. CSS floats were originally designed for inline content to flow around - like images in a long textual article - and not for grid layouts and the like. Unless you're specifically targeting old (not Edge) Internet Explorer, your target browsers support flexbox, so it's worth the time to learn.
This doesn't support IE7. You shouldn't be supporting IE7. Doing so continues to expose users to unfixed security exploits and makes life harder for all other web developers, as it reduces the pressure on users and organisations to switch to safer modern browsers.
This clearfix was announced and explained by Thierry Koblentz in July 2012. It sheds unnecessary weight from Nicolas Gallagher's 2011 micro-clearfix. In the process, it frees a pseudo-element for your own use. This has been updated to use display: block rather than display: table (again, credit to Thierry Koblentz).
I recommend using the following, which is taken from http://html5boilerplate.com/
/* >> The Magnificent CLEARFIX << */
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.clearfix {
display: inline-block;
}
* html .clearfix {
height: 1%;
} /* Hides from IE-mac \*/
.clearfix {
display: block;
}
The overflow property can be used to clear floats with no additional mark-up:
.container { overflow: hidden; }
This works for all browsers except IE6, where all you need to do is enable hasLayout (zoom being my preferred method):
.container { zoom: 1; }
http://www.quirksmode.org/css/clearing.html
I've found a bug in the official CLEARFIX-Method:
The DOT doesn't have a font-size.
And if you set the height = 0 and the first Element in your DOM-Tree has the class "clearfix" you'll allways have a margin at the bottom of the page of 12px :)
You have to fix it like this:
/* float clearing for everyone else */
.clearfix:after{
clear: both;
content: ".";
display: block;
height: 0;
visibility: hidden;
font-size: 0;
}
It's now part of the YAML-Layout ... Just take a look at it - it's very interesting!
http://www.yaml.de/en/home.html
This is quite a tidy solution:
/* For modern browsers */
.cf:before,
.cf:after {
content:"";
display:table;
}
.cf:after {
clear:both;
}
/* For IE 6/7 (trigger hasLayout) */
.cf {
zoom:1;
}
It's known to work in Firefox 3.5+, Safari 4+, Chrome, Opera 9+, IE 6+
Including the :before selector is not necessary to clear the floats,
but it prevents top-margins from collapsing in modern browsers. This
ensures that there is visual consistency with IE 6/7 when zoom:1 is
applied.
From http://nicolasgallagher.com/micro-clearfix-hack/
Clearfix from bootstrap:
.clearfix {
*zoom: 1;
}
.clearfix:before,
.clearfix:after {
display: table;
line-height: 0;
content: "";
}
.clearfix:after {
clear: both;
}
I just use :-
.clear:after{
clear: both;
content: "";
display: block;
}
Works best and compatible with IE8+ :)
Given the huge amount of replies I was not gonna post. However, this method may help someone, as it did help me.
Stay way from floats whenever possible
It's worth to mention, I avoid floats like Ebola. There are many reasons and I am not alone; Read Rikudo answer about what is a clearfix and you'll see what I mean. In his own words: ...the use of floated elements for layout is getting more and more discouraged with the use of better alternatives...
There are other good (and sometimes better) options out there other than floats. As technology advances and improves, flexbox (and other methods) are going to be widely adopted and floats will become just a bad memory. Maybe a CSS4?
Float misbehavior and failed clears
First off, sometimes, you may think that you are safe from floats until your lifesaver is punctured and your html flow starts to sink:
In the codepen http://codepen.io/omarjuvera/pen/jEXBya below, the practice of clearing a float with <div classs="clear"></div> (or other element) is common but frown upon and anti-semantic.
<div class="floated">1st</div>
<div class="floated">2nd</div>
<div class="floated">3nd</div>
<div classs="clear"></div> <!-- Acts as a wall -->
<section>Below</section>
CSS
div {
border: 1px solid #f00;
width: 200px;
height: 100px;
}
div.floated {
float: left;
}
.clear {
clear: both;
}
section {
border: 1px solid #f0f;
}
However, just when you thought your float is sail worthy...boom! As the screen size becomes smaller and smaller you see weird behaviors in like the graphic below (Same http://codepen.io/omarjuvera/pen/jEXBya):
Why should you care?
Roughly, about 80% (or more) of the devices used are mobile devices with small screens. Desktop computers/laptops are no longer king.
It does not end there
This is not the only problem with floats. There are many, but in this example, some may say all you have to do is to place your floats in a container. But as you can see in the codepen and graphic, that is not the case. It apparently made things worst:
HTML
<div id="container" class="">
<div class="floated">1st</div>
<div class="floated">2nd</div>
<div class="floated">3nd</div>
</div> <!-- /#conteiner -->
<div classs="clear"></div> <!-- Acts as a wall -->
<section>Below</section>
CSS
#container {
min-height: 100px; /* To prevent it from collapsing */
border: 1px solid #0f0;
}
.floated {
float: left;
border: 1px solid #f00;
width: 200px;
height: 100px;
}
.clear {
clear: both;
}
section {
border: 1px solid #f0f;
}
As for the result?
It's the *** same!
Least you know, you'll start a CSS party, inviting all kinds of selectors and properties to the party; making a bigger mess of your CSS than what you started with. Just to fix your float.
CSS Clearfix to the rescue
This simple and very adaptable piece of CSS is a beauty and a "savior":
.clearfix:before, .clearfix:after {
content: "";
display: table;
clear: both;
zoom: 1; /* ie 6/7 */
}
That's it! It really works without breaking semantics and did I mention it works?:
From the same sample...HTML
<div class="clearfix">
<div class="floated">1st</div>
<div class="floated">2nd</div>
<div class="floated">3nd</div>
</div>
<section>Below</section>
CSS
div.floated {
float: left;
border: 1px solid #f00;
width: 200px;
height: 100px;
}
section {
border: 4px solid #00f;
}
.clearfix:before, .clearfix:after {
content: "";
display: table;
clear: both;
zoom: 1; /* ie 6/7 */
}
Now we no longer need <div classs="clear"></div> <!-- Acts as a wall --> and keep the semantic police happy. This is not the only benefit. This clearfix is responsive to any screen size without the use of #media in it's simplest form. In other words, it will keep your float container in check and preventing floodings. Lastly, it provides support for old browsers all in one small karate chop =)
Here's the clearfix again
.clearfix:before, .clearfix:after {
content: "";
display: table;
clear: both;
zoom: 1; /* ie 6/7 */
}
I always float the main sections of my grid and apply clear: both; to the footer. That doesn't require an extra div or class.
honestly; all solutions seem to be a hack to fix a rendering bug ... am i wrong?
i've found <br clear="all" /> to be the easiest, simplest. seeing class="clearfix" everywhere can't stroke the sensibilities of someone who objects to extraneous markeup elements, can it? you're just painting the problem on a different canvas.
i also use the display: hidden solution, which is great and requires no extra class declarations or html markup ... but sometimes you need the elements to overflow the container, for eg. pretty ribbons and sashes
.clearFix:after {
content: "";
display: table;
clear: both;
}
A new display value seems to the job in one line.
display: flow-root;
From the W3 spec: "The element generates a block container box, and lays out its contents using flow layout. It always establishes a new block formatting context for its contents."
Information:
https://www.w3.org/TR/css-display-3/#valdef-display-flow-root
https://www.chromestatus.com/feature/5769454877147136
※As shown in the link above, support is currently limited so fallback support like below may be of use:
https://github.com/fliptheweb/postcss-flow-root
With SASS, the clearfix is:
#mixin clearfix {
&:before, &:after {
content: '';
display: table;
}
&:after {
clear: both;
}
*zoom: 1;
}
and it's used like:
.container {
#include clearfix;
}
if you want the new clearfix:
#mixin newclearfix {
&:after {
content:"";
display:table;
clear:both;
}
}
With LESS (http://lesscss.org/), one can create a handy clearfix helper:
.clearfix() {
zoom: 1;
&:before {
content: '';
display: block;
}
&:after {
content: '';
display: table;
clear: both;
}
}
And then use it with problematic containers, for example:
<!-- HTML -->
<div id="container">
<div id="content"></div>
<div id="sidebar"></div>
</div>
/* LESS */
div#container {
.clearfix();
}
Using overflow:hidden/auto and height for ie6 will suffice if the floating container has a parent element.
Either one of the #test could work, for the HTML stated below to clear floats.
#test {
overflow:hidden; // or auto;
_height:1%; forces hasLayout in IE6
}
<div id="test">
<div style="floatLeft"></div>
<div style="random"></div>
</div>
In cases when this refuses to work with ie6, just float the parent to clear float.
#test {
float: left; // using float to clear float
width: 99%;
}
Never really needed any other kind of clearing yet. Maybe it's the way I write my HTML.
I have tried all these solutions, a big margin will be added to <html> element automatically when I use the code below:
.clearfix:after {
visibility: hidden;
display: block;
content: ".";
clear: both;
height: 0;
}
Finally, I solved the margin problem by adding font-size: 0; to the above CSS.
I'd float #content too, that way both columns contain floats. Also because it will allow you to clear elements inside #content without clearing the side bar.
Same thing with the wrapper, you'd need to make it a block formatting context to wrap the two columns.
This article mentions a few triggers you can use:
block formatting contexts.
A clearfix is a way for an element to automatically clear after itself,
so that you don't need to add additional markup.
.clearfix:after {
content: " "; /* Older browser do not support empty content */
visibility: hidden;
display: block;
height: 0;
clear: both;
}
.cleaner {
clear: both;
}
Normally you would need to do something as follows:
<div style="float: left;">Sidebar</div>
<div class="cleaner"></div> <!-- Clear the float -->
With clearfix, you only need to
<div style="float: left;" class="clearfix">Sidebar</div>
<!-- No Clearing div! -->
Why just trying to use css hack to do what 1 line of HTML do the job. And why not to use semantic html tu put break to return to the line?
Fo me is realy better to use :
<br style="clear:both" />
And if you don't want any style in your html you just have to use class for your break
and put .clear { clear:both; } in your CSS.
Advantage of this:
Semantic use of html for return to the line
If no CSS load it will be working
No need extra CSS code and Hack
no need to simulate the br with CSS, it's already exist in HTML
Assuming you're using this HTML structure:
<div id="container">
<div id="content">
</div>
<div id="sidebar">
</div>
</div>
Here's the CSS that I would use:
div#container {
overflow: hidden; /* makes element contain floated child elements */
}
div#content, div#sidebar {
float: left;
display: inline; /* preemptively fixes IE6 dobule-margin bug */
}
I use this set all the time and it works fine for me, even in IE6.
Unlike other clearfixes, here is an open-ended one without containers
Other clearfixes either require the floated element to be in a well marked off container or need an extra, semantically empty <div>. Conversely, clear separation of content and markup requires a strict CSS solution to this problem.
The mere fact that one needs to mark off the end of a float, does not allow for unattended CSS typesetting.
If the latter is your goal, the float should be left open for anything (paragraphs, ordered and unordered lists etc.) to wrap around it, until a "clearfix" is encountered. For example, the clearfix might be set by a new heading.
This is why I use the following clearfix with new headings:
h1 {
clear: both;
display: inline-block;
width: 100%;
}
This solution gets used extensively on my website to solve the problem: The text next to a floated miniature is short and the top-margin of the next clearing object is not respected.
It also prevents any manual intervention when automatically generating PDFs from the site.
Here is an example page.
I always use the micro-clearfix :
.cf:before,
.cf:after {
content: " ";
display: table;
}
.cf:after {
clear: both;
}
/**
* For IE 6/7 only
*/
.cf {
*zoom: 1;
}
In Cascade Framework I even apply it by default on block level elements. IMO, applying it by default on block level elements gives block level elements more intuitive behavior than their traditonal behavior. It also made it a lot easier for me to add support for older browsers to Cascade Framework (which supports IE6-8 as well as modern browsers).
You could also put this in your CSS:
.cb:after{
visibility: hidden;
display: block;
content: ".";
clear: both;
height: 0;
}
*:first-child+html .cb{zoom: 1} /* for IE7 */
And add class "cb" to your parent div:
<div id="container" class="cb">
You will not need to add anything else to your original code...
#content{float:left;}
#sidebar{float:left;}
.clear{clear:both; display:block; height:0px; width:0px; overflow:hidden;}
<div id="container">
<div id="content">text 1 </div>
<div id="sidebar">text 2</div>
<div class="clear"></div>
</div>
Have you tried this:
<div style="clear:both;"/>
I haven't had any problems with this method.
My Favourite Method is to create a clearfix class in my css / scss document as below
.clearfix{
clear:both;
}
And then call it in my html document as shown below
<html>
<div class="div-number-one">
Some Content before the clearfix
</div>
<!-- Let's say we need to clearfix Here between these two divs --->
<div class="clearfix"></div>
<div class="div-number-two">
Some more content after the clearfix
</div>
</html>
It is so simple clearfix clears the issue by when we using the float properties inside the div element.If we use two div elements one as float:left; and other one as float:right; we can use clearfix for the parent of the two div element. If we refuse to use clearfix unnecessary spaces fill with contents below and site structure will be broken.

Resources