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);
Related
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>
There is a question about simple form, with input and button,
Цe need a block filled 100% of the available space inside the box in which there may be other elements, without their wraps.
This is easily done with the flexbox, but it does not support IE 8-9.
Please help me. thx, Eugene.
Using CSS table layout should give you flexibility depending of content: http://jsfiddle.net/37rxjskx/
.row {
display: table;
/* table-layout: fixed; */
/* width: 100%; */
}
.col,
button {
display: table-cell;
padding: 8px 12px;
outline: 1px dashed red;
}
<div class="row">
<div class="col">input auto 100% of the free width space</div>
<button type="submit">button<br> auto of the<br> inner content</button>
</div>
table-layout: fixed does the opposite: make browsers apply your constraints of width and ignore relative quantity of content.
Various previous answers I did on the same subject: equal width, same height, fill remaining space
Are there any hacks for max-width:-webkit-fit-content; for ie 8?
Trying to get a child div to not take up the whole width of the parent and this works well with ff, chrome and safari; hoping there's some hack to get it to work with ie 8 as well.
Fiddle showing the behavior: http://jsfiddle.net/XtZq9/
Code for the behavior I want in ie8:
#wrap {
background-color: aqua;
width:300px;
height: 50px;
padding-top: 1px;
}
.textbox {
background-color: yellow;
max-width: intrinsic;
max-width:-webkit-fit-content;
max-width: -moz-max-content;
margin-top: 2px;
}
<div id="wrap">
<div class="textbox">
Here is some text
</div>
<div class="textbox">
Here is other, longer, text
</div>
</div>
From demosthenes.info, I learned I can simply use
display: table;
instead of
width: fit-content;
Check the link however about problems with whitespaces. It does not apply to my case, and simply replacing width: fit-content with display: table solved my problem quite easily.
The closest I can think of is floating your elements. Not exactly alike, but probably sufficiently alike;) You need to set extra margin though, but this should be no problem with a conditional stylesheet.
.textbox {
background-color: yellow;
float:left;
clear:left;
}
Your modified fiddle
It might depends on the situation:
I had a block-level element with width: fit-content;. As this doesn't work on IE, the element was taking the full available width (as expected).
But I wanted it to just adjust its size to its content.
Finally, i fixed it with:
display: inline-flex;
Not yet; keep watching http://caniuse.com/#feat=intrinsic-width &
https://wpdev.uservoice.com/forums/257854-internet-explorer-platform/suggestions/6263702-css-intrinsic-sizing
I'm new to CSS tables, it's my first time. So I discovered that when you set display:table to a div, you can forgot all margin and padding (and whatever) you're planning on it's future cause they are ignored. Nice. The only property I've found to make this job is border-spacing but it is a little limited comparing with margin and padding. It have only two ways of styling, horizontal and vertical. You can't set the value of the side you want like border-spacing-left or border-spacing: 0 1px 2px 3px.
In my case, I have a table with one row that lies on the top right corner of the screen. I want it attached on the very top and spaced horizontally, which caused me problems. The top is okay but the right detaches from the border when I use border-spacing: 10px 0.
Smart guys like me don't see this as a problem, cause we can set it margin-right negatively, making it be attached again on the right side of the browser. Wow, whata smart ass I am!
However, I saw an little damn scrollbar on the bottom of the screen like a roach under your cooker at the kitchen. I hate roac.. scrollbars specially horizontals, so I got my inseticide called overflow-x and kil.. set it to hidden. She run desperately and dissapeared, but I know that she's there, somewhere staring at me. And this is driving me crazy.
Seriously now. I think this isn't the right way to do that and I hope somebody can teach me how to do it.
This is my scenario on Fiddle
Thank you in advance(mainly for reading this crap).
There are a few ways of achieving what you're trying to achieve. Most commonly, using display: table, display: table-cell, etc isn't very high on the list.
So, here's how I would do it: http://jsfiddle.net/VKnQZ/1/
Do bear in mind that I don't know the full circumstance of what you're attempting so it may well be that I'm missing a (valid) reason that you're using table display properties in the first place.
You'll notice a few things here:
I've done away with your table display properties. I don't think you need them, and floats do the job just fine (just remember to clear them).
I've removed your display from the cell divs. As someone in the comments above pointed out, divs inherit display: block by default. The additional dimensions set their size as you already had it.
I'm using the + selector to put in the spacing between elements. In this instance div + div is essentially short-hand for 'every div which is beside another div' - so all of them aside from the first.
Hopefully that achieves what you're aiming for and does away with all the nasty hacky overflow/margins/etc.
Here's the code:
HTML (only change is to remove the row div):
<div id="nav">
<div class="red"></div>
<div class="green"></div>
<div class="blue"></div>
</div>
CSS:
body {
padding: 0;
margin: 0;
}
#nav {
float: right;
}
#nav div {
float: left;
width: 120px;
height: 40px;
}
#nav div + div{
margin-left: 10px;
}
.red { background-color:#f00 }
.green { background-color:#0f0 }
.blue { background-color:#00f }
and can you tell me why are you trying to imitate table behavior when you have "table" tag? it could be styled pretty well also
what you are doing is sometimes called "divitis"
edit:
you can position table absolutely http://jsfiddle.net/n83kT/
Not too sure if this the right place to discuss float and display :)
But , flex is on his way, and display is already quiet efficient.
Display + direction and you could kick floats away.
border-spacing version : http://jsfiddle.net/GCyrillus/2EZ3F/
border-left version : http://jsfiddle.net/GCyrillus/2EZ3F/1/
<section>
<div id="nav">
<div class="red"></div>
<div class="green"></div>
<div class="blue"></div>
</div>
</section>
section is to set direction .. or not
unset & reset direction to fake float ,
else use text-align if you dislike this method.
In CSSheet, notice inline-table instead of table so it reacts to text-align and or direction (not all pages are EN or FR :) )
body {
padding: 0;
margin: 0;
}
section {
direction:rtl; /* unset regular if you wish, else text-align will do for inline-boxes */
}
#nav {
direction:ltr;/* reset/set here if you want cells from left to right */
display:inline-table;
border-spacing: 10px 0 ;
}
#nav div {
/*direction:ltr; reset here if you want cells from right to left */
display: table-cell;
width: 120px;
height: 40px;
}
#nav div + div {
margin-left: 10px;
}
.red {
background-color:#f00
}
.green {
background-color:#0f0
}
.blue {
background-color:#00f
}
My 2 (late) cents for a different point of view :)
For completeness, I would like to offer the case for the often overlooked inline-block display type.
Similar to the use of floats, the HTML is as follows:
<div id="nav">
<div class="red"></div>
<div class="green"></div>
<div class="blue"></div>
</div>
and the CSS:
#nav {
position:absolute;
top:0;
right:0;
}
#nav div {
width: 120px;
height: 40px;
display: inline-block;
vertical-align: bottom;
}
#nav div + div {
margin-left: 10px;
}
This inline-block approach behaves similarly to the floated-child-div's approach.
In this application, I can't think of a reason to use one over the other.
One minor consideration is that inline-block is not supported in some older browsers.
Otherwise, both approaches use the same mark-up and the CSS rules are similarly simple.
The choice may depend a lot on the content that you use in the #nav div elements.
Demo fiddle: http://jsfiddle.net/audetwebdesign/EVJPN/
I want to put padding on a css border. Pull it inside a div, away from the edge. Is this possible using css (css3 is fine, webkit).
Here is the design.
I did this by placing a div inside a div, then give a border to the inner div. I want to make the markup slim as posible so I want to use only one div if posible.
Thank you.
You should be able to do this with the CSS outline property:
<style>
.outer {
outline: 2px solid #CCC;
border: 1px solid #999;
background-color: #999;
}
</style>
<div class="outer">
example
</div>
Instead of borders, you may use outline property:
div{
height:300px;
width:500px;
background-color:lightblue;
outline:dashed;
outline-offset:-10px;
}
<div></div>
http://jsfiddle.net/H7KdA/
Padding around the border (which would separate it from the edge) is called the 'margin': for further details, see Box model.
Unfortunately, without adding another div, I don't think you can do this with just CSS.
The more complicated your design gets, the more likely you will need extraneous html tags.
Your other (also not great) option is an image background, or if it somehow makes you feel better, you can add elements client side with JQuery, thereby maintaining the "purity" of your server side files.
Best of luck.
You could do that by creating a inner div with the borders you want and a outer div with a display: table. Something like this:
<style>
.outer {
background: #ccc;
display: table;
width: 400px;
}
.inner {
border: 2px dashed #999;
height: 50px;
margin: 5px;
}
</style>
<div class="outer">
<div class="inner">
</div>
</div>
you can define a margin for the first child element based on the parent element selector. e.g.
.outer:first-child {
margin : 10px;
}
This way any element put inside the .outer will automatically have 10px margin.
If you want this to be applied to any direct child of the outer element use "> *" instead. e.g.
.outer > * {
margin : 10px;
}
No, that's not possible. Padding, margin and border are all parts of elements, you can't give a border padding or a margin a border.
Maybe if you post an example of what you're trying to do we can come up with alternate solutions?
-update-
Looking at your example I'm afraid it's still not possible, at least not with just one div. Im not a fan of divitis either, but the extra div probably is the best option in this case.