Suggestions for CSS development practices


Conditional Content Formatting

Sometimes content should be formatted differently depending on whether other content exists alongside it. A useful way to do that is use the next adjacent sibling selector '+'. The content that should have the conditional formatting should always appear second because there is no previous sibling selector in css.

.ui.widget .image { float: left; width: 2em; } .ui.widget .content { color: #000000; } /* content is only floated if image exists */ .ui.widget .image + .content { margin-left: 3em; }

Box Shadow Inheritance

Unfortunately box shadow must be defined as a single rule, without the ability, like border, to be broken up into separate parts for positioning, color and distance. There is however one trick to allowing for a single box shadow definition to appear as multiple colors. Box shadow inherits its color from the color attribute if no color is specified.

.ui.widget { -webkit-box-shadow: 0em 0.2em 0em inset; -moz-box-shadow: 0em 0.2em 0em inset; box-shadow: 0em 0.2em 0em inset; } /* This will also have a red box shadow */ { color: #FF0000; }

Not Sure the Size? Table It

If content needs to fill a specified size exactly, but may be made up of parts with arbitrary size, it can be useful to use display table and table-cell. This will make sure the parent width is always obeyed regardless of alterations to an element's width.

Keep in mind any table-cell element must have a parent with display:table to appear formatted correctly.

.ui.input { display: table; } /* these two elements will always fill the input exactly regardlesss of the text content of the button */ .ui.input input { display: table-cell; } .ui.input .button { display: table-cell; }

Fixing Whitespace with Inline Block

In HTML usually whitespace doesn't change a page's layouts. However, when using inline block any whitespace will create unwanted space between consecutive inline-block elements. The simple and effective fix is to make sure font-size on the parent element is 0, making all whitespace 0 pixels. Then you can reset font-size on the child element to body font size or 1 relative em.

/* remove whitespace */ { font-size: 0em; } .item { display: inline-block; font-size: 1rem; }

CSS :not is Awesome

Inheritance can be hell sometimes. Consider changing the opacity of an element. There is no way to "cancel out" of that opacity change on content inside.

Sometimes the only way to avoid creating inheritance problems is to specify what elements should not receive a set of rules. Consider blurring content while a dimmer is present. Blurring should only apply to elements that are not inside the dimmer, but there is no way to know what the content is beforehand.

/* blur everything but the dimmer */ body.dimmed :not(.dimmer){ -webkit-filter: blur(15px) grayscale(0.7); -moz-filter: blur(15px) grayscale(0.7); }

Prevent Accidental Highlighting

Sometimes text can be accidentally highlighted when a user double clicks an element. No need to pull out javascript to solve this.

.ui.thingy { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }

Multiple Highlight Colors

It's fairly commonly known that you can set text selection colors in css for a page, but its less commonly known that you can use multiple highlight colors in a single page.

/* text selected turns highlighted yellow */ ::-webkit-selection { background-color: #FFFFCC; color: #555555; } ::-moz-selection { background-color: #FFFFCC; color: #555555; } ::selection { background-color: #FFFFCC; color: #555555; } /* headers selected turn red */ h1::-moz-selection, h2::-moz-selection, h3::-moz-selection { background-color: #F1C1C2; color: #222222; } h1::selection, h2::selection, h3::selection { background-color: #F1C1C2; color: #222222; }

Shading Borders

When you have colored content that needs a border to match its current color, try using a 1 pixel inset box shadow with an RGBA value.

/* this border will be grey */ .ui.thingy { -moz-box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1) inset; -webkit-box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1) inset; box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1) inset; } /* this border will be red tinted */ { background-color: #FFF8F8; }

Joining borders

Sometimes bordered content must sit next to other bordered content. If each element uses border the borders will double. Consider using either outline or a box shadow to accomplish the same effect but without overlapping borders.

/* this might not go so well */ .ui.thingy { border: 1px solid #DDDDDD; } /* rgba is great, but keep in mind the overlapping borders will be added together to create a darker shade */ .ui.thingy { outline: 1px solid rgba(0, 0, 0, 0.1); } /* classic but works */ .ui.thingy { outline: 1px solid #DDDDDD; } /* this works too */ .ui.thingy { -moz-box-shadow: 0px 0px 0px 1px #DDDDDD; -webkit-box-shadow: 0px 0px 0px 1px #DDDDDD; box-shadow: 0px 0px 0px 1px #DDDDDD; }

Using transparency

RGBA colors in css allow you to specify colors with a transparency channel. This is very useful.

Consider for example, defining the text states of an element. If the elements color changes, the text might appear more complementary as a shade of black with a portion of the original color. This can be done easily with rgba

.ui.thingy { background-color: #FAFAFA; color: rgba(0, 0, 0, 0.7); } .red.ui.thingy { background-color: #FF0000; }

Nothing is always Fixed

CSS fixed allows you to have content stick to an offset position in a page regardlesss of the scroll position of the page. Fixed menus will use the page as the offset parent, in all circumstances except when css transform is used on a parent element. This will change the offset context to the transformed element instead of the page.

This behavior may seem unexpected, but using this quirk can allow you to have fixed position content relative to any element in a page.

.ui.content { transform: rotateZ(0deg); overflow: scroll; } /* fixed will stay in its current offset relative to the parent container */ .ui.content .fixed.thingy { position: fixed; top: 0px; width: 100%; }

Centering Content with Transform

Using percentages in CSS will give you a ratio based on the size of the parent element. For example, setting content to be left 50% will set content to start at exactly halfway across its parent.

If you want content to positioned relative to its own size use CSS transform with translate. Percentages specified inside a transform are unique in that they are based on the current element size not its parent.

/* doesnt work */ .ui.modal { width: 800px; height: 500px; left: 50%; top: 50%; margin: -50% 0px 0px -50%; } /* works with measurements */ .ui.modal { width: 800px; height: 500px; left: 50%; top: 50%; margin: -250px 0px 0px -400px; } /* with transform no measurements needed */ .ui.modal { position: absolute; width: 800px; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); }

Consider alternatives to floats

CSS floats can create issues with the containing element not receiving the size of its children. Using overflow:hidden to clear floats means that no piece of an element can be shown outside the bounding box of the element, which limits the possibilities in an element. Clearfixes can use up one of two available pseudo class which can often be useful for styling elements.

Consider using another means of putting content side by side like inline-block or table-cell. These provide more freedom than floated block elements, and can add additional benefits.

To avoid issues with inline-block causing spacing between elements, specify no font size on the group and 1rem on the floated content

/* not the best */ .ui.thingy { display: block; overflow: hidden; } .ui.thingy .part { display: block; float: left; } /* these do the same thing */ .ui.thingy { display: block; font-size: 0rem; } .ui.thingy .part { display: inline-block; font-size: 1rem; }

Onion Skinning

One technique that is useful for allowing for multiple color variations of an element, without having to completely reskin each variation and shade is to use background-image gradients to define shading and state, and background-color to define the color of an element. If done well you can add a variety of colors with very little code.

.ui.thingy { background-color: #FAFAFA; } { background-color: #FF0000; } { background-color: #00FF00; } { background-color: #0000FF; } .ui.thingy:hover { background-image: -webkit-gradient(linear, 0 0, 0 100%, from(rgba(0, 0, 0, 0.1)), to(rgba(0, 0, 0, 0.05))) ; background-image: -webkit-linear-gradient( rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.05) 100%) ; background-image: -moz-linear-gradient( rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.05) 100%) ; background-image: -o-linear-gradient( rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.05) 100%) ; background-image: linear-gradient( rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.05) 100%) ; }

Style Guide

Don't Hyphenate

All elements are designed to include their own namespace. As long as rules descend from their parent element there is no possibility of rule collision.

Hyphenated class names often describe the intersection of separate concepts, and can be better written to represent each concept separately.

/* no no no */ .ui.button-active-red { background-color: #FF0000; font-weight: bold; color: #FFFFFF; } /* better */ .red.ui.button { background-color: #FF0000; color: #FFFFFF; } .active.ui.button { font-weight: bold; }

CSS Legibility

Adding extra formatting can help increase clarity in your code. We suggest separating css selectors on separate lines, adding a space after css properties with commas (like box-shadow) and placing a zero before any decimal value.

/* not so easy to read */ .ui.widgets .widget, ui.widget, .ui.widget.type, ui.widgets .widget.type { color: #FFFFFF; } /* this should have spaces after commas and a zero before any decimal value */ .ui.widget { color:rgba(0,0,0,.3); } /* easier to read */ .ui.widgets .widget, .ui.widget, .ui.widgets .widget.type, .ui.widget.type { color: #FFFFFF; } /* properly formatted */ .ui.widget { color: rgba(0, 0, 0, 0.3); }

Keep Things Ordered

Although css rule order may be considered a chore, grouping related rules together can help keep css code organized.

An easy way to do this is to consider ordering rules from the outside in. First describing positioning rules, then border rules, margin, sizing, padding, font-size, line height and ending with vendor prefixed attributes.

/* not so easy to read */ .ui.widgets .widget, ui.widget, .ui.widget.type, ui.widgets .widget.type { color: #FFFFFF; } /* more legible */ .ui.widgets .widget, .ui.widget, .ui.widgets .widget.type, .ui.widget.type { color: #FFFFFF; } /* i have some extra time so lets group these rules */ .ui.widget { position: relative; top: 0em; left: 0em; margin: 1em; border: 1px solid rgba(0, 0, 0, 0.1); width: 100px; height: 100px; padding: 1em; font-size: 1.2em; color: rgba(0, 0, 0, 0.8); line-height: 1.2em; -webkit-border-radius: 0.3em; -moz-border-radius: 0.3em; border-radius: 0.3em; }

Avoid non-semantic tags, make wrappers groups

UI elements should be designed to include the minimum footprint of an element. If extra styling is needed, consider using pseudo selectors :after and :before. This allows for the creation of two extra divs inside each div context which can almost always be enough to accommodate extra styling.

If there is no other option than wrapping content in a containing HTML element, consider using a singular/plural relationship by having the wrapper describe its contents instead of an arbitrary class name like wrapper

/* not tops */ .ui.message .wrapper .title, .ui.message .wrapper .description { } /* better */ .ui.message .content .title, .ui.message .content .description { }


Adding default margins to your content allow for it to have vertical rhythm in a page, but be careful about forcing margin in all circumstances. Here's a useful way to make sure content inside container elements doesn't receieve unnecessary padding.

.ui.thingy { margin: 1em 0em; } .ui.thingy:first-child { margin-top: 0em; } .ui.thingy:last-child { margin-bottom: 0em; }

Grammatical order

Consider using similar class syntax as if you were actually describing the element in English. Although this is by no means required it may help provide clarity in some circumstances.

/* confusing word order */ { } /* much more semantic */ .red.pointing.ui.button { }

Use Border Box

Border box fixes the box model, and allows padding to be included as part of width and height definitions. Using it opens up another world of possibilities for sizing content to fit fluidly

.two.ui.thingies .ui.thingy { width: 50%; padding: 1em; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; }

Units and Measurements

Unit Consistency

CSS provides a broad selection of measurements for values. It is helpful to keep unit definitions consistent across a single property definition. Including consistent units for 0 values also allows for quicker tweaking and shows greater precision in a property definition.

/* not tops */ .ui.widget { padding: 0 16px .6em; } /* hex are uppercase */ .ui.widget { color: #09ffda; } /* good */ .ui.widget { padding: 0em 0em 0em 0.2em; color: #009FDA; }

Inheritance is Magical

Many CSS properties can use the value 'inherit' to specify, quite unintuitively, to take on the value of parent element for values that do not normally inherit. For example, an element can use inherit to double whatever its parents padding size is, or to receive the same type of border as a parent without knowing what it is beforehand.

/* inheriting borders */ .ui.widget { border: 2px solid rgba(0, 0, 0, 0.1); } /* will receive same border treatment as parent */ .ui.widget .foo { border: inherit; } /* inheriting positioning */ .ui.widget { padding: 0.5em 1em; } /* will use the same padding as parent */ .ui.widget .foo { padding: inherit; }

Relatively Relative

EMs are defined so that 1em is equal to the current font size inside of an element. Using EMs can allow you to size content inside an element in proportion to the overall size of the element. Be careful though because this will stack with nested elements.

.ui.thingy { font-size: 14px; } /* this is 28 pixels */ .ui.thingy .thing { font-size: 2em; } /* woah this is now 48 pixels */ .ui.thingy .thing .thing { font-size: 2em; } /* .ui.thingy .thingy should grow as well */ .ui.large.thingy { font-size: 16px; }

Recursively Relative

Using EMs multiplicative nature can be used to your advantage. Instead of defining multiple tiers of a menu system, consider using ems to reduce each tier's sizing. As you continue to nest menu elements each nested menu will compute its values with smaller proportions. { font-size: 1rem; } .menu { margin-left: 0.5em; font-size: 0.9em; }

Absolutely Relative

Relative EMs (rems) are calculated relative to the font size of the entire page. This is needed to explain how content should be sized related to the overall size of elements on the page, and will not increase geometrically when nested like EMs.

/* i am a weird page with very tiny fonts */ html { font-size: 10px; } /* thats ok i am sizing everything relative to your tiny fonts */ { font-size: 1rem; } /* i am sizing relative to the menu element */ .menu { font-size: 0.8em; } /* i am the same size as the rule above */ .menu .menu { font-size: 0.8em; }