(Dev10) WD: Section 3.2: CSS: Intro, Values
General Sibling
The general sibling selector uses the tilde '~' symbol and unlike the adjacent sibling, it will select all elements following the specified element at the same level of the document. .disclaimer ~ p { color: red } Now all sibling paragraphs would be red: <p>Not red colored</p> <div class="disclaimer"> <p>Not red colored.</p> <div> <p>Not red colored.</p> </div> </div> <p>This would be red colored, it is a sibling.</p> <p>This would be red colored, it is a sibling.</p>
why is viewport important?
The viewport is an important part of sizing and layouts for CSS. Simply put, the viewport is the user's visible area of the web page. It varies by device because a mobile phone has a smaller viewport than a desktop computer monitor. Before the rise of mobile phone and tablet devices, pages were only designed for computer screens, so layouts were fixed sizes. However, these sizes are much too large for smaller viewports which led to very difficult to read and navigate sizes when they were loaded on mobile devices.
Combining Selectors
To keep things simple, we initially demonstrated single selectors, however, it is very common to combine selectors to get more granular in our targeting. You can use CSS to target descendants, children, adjacent, and general elements. In our examples, we will only show two levels to keep things simple, but you can go as many levels deep as your brain can keep track of. (Most people prefer not to go more than 3 levels deep on a selector).
Hexadecimal Values (color)
A hexadecimal value starts with a hashtag symbol followed by six hexadecimal numbers. A hexadecimal number is base 16 which means instead of going from 0 to 9 in each position it goes from 0 to f (a is 10, b is 11, ... f is 15). This is the most common way for web developers to express color, and it gives a lot more control over the shade and hue of the color than using color names does.
Absolute Lengths
Absolute lengths can be expressed in a variety of ways, but in practical usage you will generally only see px (pixels): cm Centimeters (96px) mm Millimeters (9.6px) Q Quarter-millimeters (24px) in Inches (243.84px) pc Picas (40.64px) pt Points (3.39px) px Pixels (1/96 inch) Note that pixels are not actual pixels on the display device, since some devices have higher DPI (dots per inch) than others. They are relative to the viewing device, so on a high resolution screen 1px implies multiple physical pixels.
Relative Units
As we mentioned above, relative units are relative to something else. The benefit of using relative units is scale. This means that with some careful planning you can make it so the size of elements will change relative to everything else on the page so that resizing flows throughout your document. Here are some of the more common relative units: em: Relative to the font size of the parent. These units are preferred for non-print layout font sizes because of scaling. For example, 2.5em is 2.5 times larger than the parent's font size. rem: Relative to the root element's font-size. lh: Relative to the line height of the element. vw: 1% of the viewport width. (ex: 30vw is 30% of the viewport width) vh: 1% of the viewport height. The viewport is an important part of sizing and layouts for CSS. Simply put, the viewport is the user's visible area of the web page. It varies by device because a mobile phone has a smaller viewport than a desktop computer monitor.Before the rise of mobile phone and tablet devices, pages were only designed for computer screens, so layouts were fixed sizes. However, these sizes are much too large for smaller viewports which led to very difficult to read and navigate sizes when they were loaded on mobile devices. Let's look at an example in the lengths.html file. Here we have added a <div> element with a few paragraphs inside it that we have assigned CSS classes to in order to demonstrate a few of the units: <h1>Relative and Absolute units</h1> <div class="container"> <p class="absolute">I am 150px wide</p> <p class="viewport">I am 30vw wide</p> <p class="em">I am 25em wide</p> </div> For the CSS, we have added the following styles: .container { font-size: 1em; } div > p { border: 1px solid black; } .absolute { width: 150px; } .viewport { width: 30vw; } .em { width: 25em; } If you open the file in a browser, you will find that if you change the size of the browser window, the viewport paragraph's border will shrink and grow with the size of the browser window. The container's font size of 1em means that the font size of the paragraphs will be whatever the default font size is set for in your browser. Try editing the file and changing the value to 1.5 and you will see all of the font sizes in the container grow proportionally larger as well as the width of the em paragraph.
Calculating Specificity
Browsers have a way of calculating the specificity of any rule so that they can score conflicts. This score is a 4 digit number. Depending on the type of selector(s), values are added to the ones, tens, hundreds, or thousands digit. Thus, when multiple rules select the same element and there is a conflict, the property with the higher specificity calculation wins. If there is a tie, the one defined last wins. Here are the score columns: Thousands A rule declared in the style attribute of an element gets a score of 1000. In short, this means you can override any rules in the head or in a CSS file by placing a style directly on the HTML element. Hundreds A rule that targets the id selector gets a score of 0100. This is why putting id attributes on elements that need to be styled uniquely is a common technique. Tens Rules grant a tens score for each class selector, attribute selector, or pseudo-class selector in a combinator or overall selector expression. Ones The lowest level of specificity gives a point for each element or pseudo-element selector. Let's look at some example selectors and their calculated specificity:
Cascade, Specificity, and Inheritance
CSS styles cascade, it's part of the name after all. This means that the order of CSS rules matter. This means that if two rules with the same specificity both target the same element, the rule that was defined last is the one that will be used. The CSS rule that was defined last is the one that will be applied. To demonstrate, let's look at a contrived example. Say we duplicate the same CSS selector in a file with different values: h1 { color: blue; } h1 { color: green; } The <h1> tags in any document these styles were applied to would show up as green, since these two definitions have the same specificity and the green value was defined after the blue value. If you haven't figured out what we mean by specificity, in lay terms it is a score that is applied to a rule. When multiple rules target the same element, any conflicts where the same property appears will be resolved by choosing the value with the higher specificity score. The same property part is important! If two rules target the same element with different properties, all of the properties will apply, it is only on conflicting properties that specificity comes into play. By inheritance, we mean that some CSS property values set on a parent element are automatically applied to their child elements. An example of this is the font-family property. If you were to set this on the <body> element, then all elements contained in the HTML document would inherit that same font-family value by default. Conversely, the width property does not inherit. So if you were to set a width of 75% on an element, its child elements will not also get a width of 75%, they will keep their default width setting. There are too many CSS properties to list here, but if you look at the documentation for any CSS property online at W3C or Mozilla Developer Network, it will usually tell you whether a specific property is inherited or not.
RGB Values (color)
For RGB, you must use the rgb() function. This function takes three values, a value for the red, green, and blue channels respectively. There is also a rgba() function which takes a fourth value for the opacity. Here is an example of the same purplish color in hexadecimal and rgb: .rgbpurple { color: rgb(197, 93, 161); } .hexpurple { color: #c55da1; } .rgbapurple { color: rgba(197, 93, 161, 0.6); } A difference between setting the opacity property and using rgba is that opacity effects the entire element and everything inside it whereas rgba() only effects the color.
Inner, Outer, Flex, and Grid
It's important to take a moment and talk about display types. With regards to block and inline, we are referring to the outer display type. Boxes also have an inner display type which dictates how elements inside the box are laid out. By default, this is set to something called normal flow, which means they behave as we described above based on their block or inline type. A neat feature of CSS is that we can override the inner display by using values like flex or grid. So if you have a block element, such as a <div> and you set its display property to flex, the direct children of the box will become flex items and their layout will be governed by the flexbox spec which is a one-dimensional layout method for organizing things into rows and columns. Unsurprisingly, the grid value is a way of managing layouts as if they are a grid. A deep dive into flex and grid layouts cross a line from web developer to designer, so we will not be covering this topic in detail in this course. Most developers prefer to use one of the many CSS frameworks that have pre-built layout classes in them.
Calculations
Lastly, you can use the calc() function if you require more than just a standard percentage or other relative value. Consider the following: .offset { width: calc(20% + 100px); } If you ever have a scenario where you do not know the container element's size in advance you can use the calc() function to do the math in real-time. This is not a very common technique because it is so difficult to anticipate what values will be injected at runtime.
Lengths and Sizing
Lengths, whether width or height, are a numeric type that you will come across frequently. There are two ways to express lengths in CSS: absolute and relative. An absolute length is a specific measurement that is always considered to be the same size regardless of any parent elements, viewport size, etc. A relative length is a length in relation to something else, usually the size of the parent element or the size of the viewport or screen.
CSS intro final thoughts
Now that we understand the mechanics of how selectors are defined, rules are applied, and how conflicts are resolved, we need to point out a few things: Every browser has a default style sheet. This means HTML element appearance may be different across browsers if you do not set styles. It is not uncommon for web developers to link a CSS Reset stylesheet first that removes all these default styles for consistencies. Users can also apply their own stylesheets. This is common for users with visual impairments that want larger fonts and such. (This is another legitimate use of the !important value) So in a way, as a web developer, you are overriding the browser styles and users may override your styles by using the principles of cascading, inheritance, and specificity.
Numeric Values
Numeric values in CSS will either be whole numbers or decimals. They are never surrounded by quotes or any other symbols, though it is common to prefix decimals with a 0 if they are less than one: .overlay { opacity: 0.6 } If you are not familiar with the opacity property it sets the transparency of an element and accepts values between 0 (fully transparent) and 1 (fully opaque).
A Flex Example
One common use of the flex property is to use unordered lists to create top navigation bars. By default, the <ul> and <li> elements are block elements and stack vertically, but we can change this behavior by assigning the display property to flex: .navbar { display: flex; list-style: none; padding: 0; } .navbar li { margin-right: 1em; } .navbar li a { text-decoration: none; } With these styles, we can use an unordered list to contain links, which are now inline instead of vertical: <ul class="navbar"> <li><a href="#">Link 1</a></li> <li><a href="#">Link 2</a></li> <li><a href="#">Link 3</a></li> </ul> We will cover the CSS properties we used to restyle the list and remove things like bullets and the default underlining in links in a later lesson, but you can see how the rendering is radically different than the out of the box <ul> and <li>. If for some reason you wanted to have a block element behave like an inline element or for an inline element to behave like a block element, you can simply set their display properties to inline or block: .inline { display: inline; } .block { display: block; } This HTML will lay out a bit differently than what is the default: <p>This content will be <span class="block">broken up</span> by a span acting like a block element.</p> <p class="inline">This paragraph will be inline with </p> <p class="inline">this paragraph.</p>
Margin Collapsing
One thing that catches beginners off guard is that margins collapse. This means if you have two elements whose margins touch, their margins will collapse if they are both positive to the largest of the two values. If one or both is negative, they will subtract the values. For example, consider the following: .p1 { margin-bottom: 30px; } .p2 { margin-top: 50px; margin-bottom: 30px; } .p3 { margin-top: -20px; } If we were to decorate some paragraph tags like this: <p class="p1">Paragraph 1</p> <p class="p2">Paragraph 2</p> <p class="p3">Paragraph 3</p> The margin between p1 and p2 would be 50px, because of margin collapsing. However the margin between p2 and p3 would be 10px, as the result of 30px-20px.
More on Padding
Padding is the space between the border and the content area. You cannot have negative values for padding, but you can set it to zero. One thing to note is that any background image or color applied to your content will display behind the padding. Regardless, padding is appropriate to set when you are trying to push content away from the border. Padding works a lot like the margin property in syntax and options: /* all sides */ padding: 10px; /* vertical, horizontal */ padding: 10px 5px /* top right bottom left */ padding: 0 20% 0 20% Much like margin, you can also individually specify padding for directions: padding-top: 0; padding-right: 20%; padding-bottom: 0; padding-left: 20%;
Percentage Values
Percentages are always relative as they will be set based upon some other value. These can be used for many property types including font sizes, though more commonly they are used for width and height properties. For example, if you have a CSS class with a width of 50%, it will be half the size of its parent container. If the parent container is also 50% width and is a root element, it will be 50% of the viewport and the inner element will be 50% of that (25% of the viewport). This allows you to keep elements proportional when the viewport is resized.
Using !important
Sometimes, if specificity isn't working out for you, you can override the calculations and brute-force a value. This is not a recommended technique, but can be used as a last resort: .override { color: red !important; } By placing the !important rule on the style declaration it overrides all other style declarations. We typically avoid doing this because it makes debugging issues more difficult. In general, the only time it may be ok to use !important is when you need to override a style that is coming from an external source, like a CSS library (bootstrap, material, etc.). We will look at libraries in a later lesson. The !important setting will also override inline styles. But again, this rule should only be used as a last resort. First, you should do everything you can to restructure your HTML and CSS rules such that !important is not needed.
CSS Box Model
The box model is a paradigm for laying out blocks of content on the page in a browser. It accounts for content, padding, borders and margins.
Child Combinator
The child combinator only selects elements that are first-level children of the specified element. Let's use the same HTML as the descendant combinator above to illustrate the difference: .disclaimer > p { color: red } As you can see, instead of a space, we put an angle bracket > character between the selectors. Let's see how this impacts the content: <div class="disclaimer"> <p>This content would be red colored.</p> <div> <p>This content is not red colored, it is not a direct child since it is in a div.</p> </div> </div> <p>This content would not be red colored.</p>
Descendant Combinator
The descendant combinator utilizes a space between selectors and will match elements that are descendants (nested inside) elements. You specify descendants by putting a space between the elements. Consider this example: .disclaimer p { color: red } The above would select paragraph elements nested inside an element with a class of disclaimer: <div class="disclaimer"> <p>This content would be red colored.</p> <div> <p>This content would also be red colored, since it is a descendant of the disclaimer element.</p> </div> </div> <p>This content would not be red colored.</p>
Images
The image data type is used when you need to specify an image file in a CSS class. This can either be a gradient that you draw using colors and coordinates or it can be a file that you specify using a url: CSS .image { background-image: url(assets/arrow.png); background-repeat: no-repeat; width: 200px; height: 200px; } .gradient { background-image: linear-gradient(90deg, #2e8b57 39%, #9acd32 100%); width: 200px; height: 200px; } HTML <div class="image"></div> <div class="gradient"></div> Here we set the width and height of the elements because we are using empty <div> elements that without content have no size and so no background image will show up. The no-repeat is used because when you specify a background-image file, by default it will repeat the image to fill the element it is set to. This is useful to leave on when you have a color swatch or something you want to repeat throughout the element. Linear Gradients take two colors and a direction and transition from one color to the other. Since colors are really just numbers, this is something the computer can do.
More on Margins
The margin property sets the margin area on the four sides of the element. You can express margin in a variety of ways by providing one or more length values or percentages (or a mixture of) or by using the auto keyword: /* Apply to all 4 sides */ margin: 5px; /* top and bottom 0 margin, horizontally centered */ margin: auto; /* vertical, horizontal */ margin: 10px 5px /* top right bottom left */ margin: 0 20% 0 20% If you choose, you can also be more explicit about margin values with regards to the element side: margin-top: 0; margin-right: 20%; margin-bottom: 0; margin-left: 20%; If you do not specify a margin value for a side, it will use whatever the default or inherited value is. An interesting effect you can have with margins is to make them negative. By putting a negative value into a margin you can cause elements to overlap, which can be a useful effect when you wish to layer elements for visual impact. Margin Collapsing One thing that catches beginners off guard is that margins collapse. This means if you have two elements whose margins touch, their margins will collapse if they are both positive to the largest of the two values. If one or both is negative, they will subtract the values. For example, consider the following: .p1 { margin-bottom: 30px; } .p2 { margin-top: 50px; margin-bottom: 30px; } .p3 { margin-top: -20px; } If we were to decorate some paragraph tags like this: <p class="p1">Paragraph 1</p> <p class="p2">Paragraph 2</p> <p class="p3">Paragraph 3</p> The margin between p1 and p2 would be 50px, because of margin collapsing. However the margin between p2 and p3 would be 10px, as the result of 30px-20px.
Position
The position data type represents a 2D position in an element and can be used for things like text alignment or image positions. Position can accept length values, percentage values, and keywords such as top, bottom, left, right, and center. For example, let's look at the background-position property for some examples: CSS .box { width: 600px; height: 200px; border: 1px solid black; } .centered { background-image: url(assets/arrow.png); background-repeat: no-repeat; background-position: center; } .middle-right { background-position: right; background-image: url(assets/arrow.png); background-repeat: no-repeat; } .offset-left-bottom { background-image: url(assets/arrow.png); background-repeat: no-repeat; background-position: left 2em bottom 1em; } HTML <div class="box centered"></div> <div class="box middle-right"></div> <div class="box offset-left-bottom"></div> As you can see in the offset example, we can mix and match length values and position keywords to specify offsets. So the arrow in the final <div> element is 2em from the left and 1em from the bottom of the container. We encourage you to play with this example and see how you can move the position of the arrow around. For example, can you center it without using the center keyword?
The Standard Box Model
The standard box model applies to block boxes, with inline boxes only using some of the behavior. The makeup of any box has 4 sub-boxes working from outside to inside: Margin The margin is the outermost box and serves as whitespace between the box and other elements. Its size is controlled by using the margin CSS properties. Border The border-box starts on the inside of the margin, wrapping the content and padding. Its size and style can be set by using border CSS properties. Padding Padding is whitespace around the content but inside the border. Its size is controlled by using the padding CSS properties. Content This is where the actual content is displayed. In general, sizing in this area is set by size properties like width and height. The thing to remember about the standard box model is that if the above diagram is a block element, if you set the width and height attributes, they apply to the content sub-box. So consider the following CSS rule: .boxspace { width: 200px; height: 100px; margin: 5px; padding: 10px; border: 1px solid black; } Using the standard box model, the actual width of the element in the HTML document would be width + left padding + right padding + left border + right border + left margin + right margin (200 + 10 + 10 + 1 + 1 + 5 + 5) 232px. The content inside the border would only be the content and the padding, 220px.
Colors
There are many ways to specify color in CSS and color values apply to things like text colors, background colors, border colors, etc. We have seen in previous examples our use of the color red to describe a color. CSS contains a variety of colors that you can call by name, you can see a list of them here: CSS Color Names. What is more common is to specify colors using a hexadecimal or RGB values. Hexadecimal Values A hexadecimal value starts with a hashtag symbol followed by six hexadecimal numbers. A hexadecimal number is base 16 which means instead of going from 0 to 9 in each position it goes from 0 to f (a is 10, b is 11, ... f is 15). This is the most common way for web developers to express color, and it gives a lot more control over the shade and hue of the color than using color names does. RGB Values For RGB, you must use the rgb() function. This function takes three values, a value for the red, green, and blue channels respectively. There is also a rgba() function which takes a fourth value for the opacity. Here is an example of the same purplish color in hexadecimal and rgb: .rgbpurple { color: rgb(197, 93, 161); } .hexpurple { color: #c55da1; } .rgbapurple { color: rgba(197, 93, 161, 0.6); } A difference between setting the opacity property and using rgba is that opacity effects the entire element and everything inside it whereas rgba() only effects the color.
Adjacent Sibling
This selector selects all elements that are adjacent siblings. That means elements that are immediately following the specified element on the same level of the document. The adjacent sibling operator is the plus symbol. Let's modify our disclaimer example: .disclaimer + p { color: red } Now only the final paragraph tag would be red: <p>Not red colored</p> <div class="disclaimer"> <p>Not red colored.</p> <div> <p>Not red colored.</p> </div> </div> <p>This content would be red colored. It is adjacent to the disclaimer class element.</p> <p>Not red colored. Same level but not adjacent.</p>
CSS Selectors
We have already demonstrated basic selectors already. The selector is the first part of a CSS rule and is a pattern that matches one or more elements in an HTML document. The five most common selectors are element, class, id, attribute, and pseudo: /* element selectors use HTML tags */ p { color: blue; } /* class selectors are added to elements using the class attribute, for example: <p class="warning">This is a warning!</p> */ .warning { color: red; font-weight: bold; } /* id selectors allow you to target a specific element by its id name, for example: <div id="disclaimer"></div> */ #disclaimer { border: 1px solid red; } /* attribute selectors let you style elements based on an attribute, usually used for forms. For example: <input type="text" id="firstname" name="firstname"> */ input[type=text] { width: 50%; } /* pseudo selectors look for a certain state or property of an element. For example if we wanted to bold a link when hovered over. */ a:hover { font-weight: bold; }
More on Borders
We have seen in previous examples how we can set a consistent border size, stroke, and color around an element. Much like margin, we can also assign individual border properties for all sides or individual sides by direction. For example: /* standard border syntax */ border: 1px solid black; /* all 4 sides, one at a time */ border-width: 1px; border-style: solid; border-color: black; /* specific side properties, (top right bottom left) */ border-top-width: 1px; border-top-style: dashed; border-top-color: blue; border-bottom-width: 2px; border-bottom-style: dotted; border-bottom-color: red; /* etc. */ It is not very common to style different sides of a border differently, because it is jarring to the user experience, but you do have the ability. As for border styles, you have several choices: none - 0 width, no visible style, but if a conflicting border is specified, it will be shown. hidden - Like none, except if there is a conflicting border, it won't be shown. dotted - A series of rounded dots. dashed - A series of rectangular dashes. double - A double line border. groove - A border with a carved appearance. ridge - A border with an extruded appearance. inset - Border makes the element appear to be embedded. outset - Border makes the element appear embossed. solid - A single, straight, solid line. If you would like a curved border, you can use the border-radius property to specify a radius curve for the top-left, top-right, bottom-right, and bottom-left corners. This works similar to the margin property.
The em and rem Units are Common
When sizing anything from containers to text the em and rem units are ones you are likely to encounter given their relative flexibility. Using them properly can save you a lot of time and effort when making changes later. As an example, consider the following CSS: html { font-size: 12px; } h1 { font-size: 1.5em; } With this setup, the default font size for all elements would be 12px and the <h1> element would be 1.5 times the size of that. Thus if you were to change the font size of the html element to 14, the <h1> tag would grow in size proportionally. The challenge with the em unit is that it looks at the parent's font size and grows or shrinks in proportion. Let's consider another example: html { font-size: 12px; } .ems li { font-size: 1.3em; } .rems li { font-size: 1.3rem; } If we have two nested lists: <ul class="ems"> <li>One</li> <li>Two <ul> <li>Two A</li> <li>Two B</li> </ul> </li> </ul> <ul class="rems"> <li>One</li> <li>Two <ul> <li>Two A</li> <li>Two B</li> </ul> </li> </ul> You will see that the nested list items in the .ems list grew in proportion to their parent, so those items are larger than the first level items. This is where the rems unit comes in. It is relative to the root element, which means it will always be relative to the <html> element's sizing, so that list looks better.
Shared Rules
You can also share rules across multiple selectors by comma separating them: label, .disclaimer { font-weight: bold; } The above CSS would apply bold font to any label elements and any elements with the disclaimer value set to the class attribute.