Web Notes
2016.08.20
Using Liquid in Jekyll - Live with Demos
Liquid is a simple template language that Jekyll uses to process pages for your site. With Liquid you can output complex contents without additional plugins.
Let’s begin with the cascade, the C in CSS. How it works and how to work with it practically.
The cascade is an algorithm that defines how to combine property values originating from different sources. It lies at the core of CSS, as emphasized by the name: Cascading Style Sheets.
Fundamentally, CSS is about declaring style rules. There are often several ways to accomplish the same thing in CSS. Depending on which solution you use, you may get wildly different results when the structure of the HTML changes, or when the styles are applied to different pages. A key part of CSS development comes down to writing rules in such a way that they’re predictable. While predicting how rules behave requires an understanding of the cascade.
When two or more rules target the same element on the page, the rules may provide conflicting declarations. For example in the following markups:
<header class="page-header">
<h1 id="page-title" class="title">Wombat Coffee Roasters</h1>
</header>
with the following CSS rules:
h1 {
font-family: serif;
}
#page-title {
font-family: sans-serif;
}
.title {
font-family: monospace;
}
The title can’t have three fonts at one time. So, which one will it be?
To determine the answer, you should know that the browser follows a set of rules, so the result is predictable. In this case, the rules dictate that the second declaration, which has an ID selector, wins; the title will have a sans-serif
font.
The cascade is the name for this set of rules. It determines how conflicts are resolved, and it’s a fundamental part of how the language works. When declarations conflict, the cascade considers three things to resolve the difference:
These rules allow browsers to behave predictably when resolving any ambiguity in the CSS.
Note that
@import
and@charset
obey specific algorithms and aren’t affected by the cascade algorithm.
There’re different types, or origins, of stylesheets. Yours are called author styles; there are also user agent styles, which are the browser’s default styles. User agent styles have lower priority.
Some browsers let users define a user stylesheet. This is considered a third origin, with a priority between user agent and author styles.
The user agent styles set things you typically want, so they don’t do anything entirely unexpected. When you don’t like what they do to a certain property, just set your own values in your stylesheet.
A declaration can be marked important by adding !important
to the end of the declaration, before the semicolon:
color: red !important;
These declarations marked with !important
are treated as a higher-priority origin, so the overall order of preference, in decreasing order, is this:
The cascade independently resolves conflicts for every property of every elements on the page.
If conflicting declarations can’t be resolved based on their origin, the browser next tries to resolve them by looking at their specificity. The browsers evaluates specificity in two parts: styles applied inline in the HTML and styles applied using a selector.
If you use an HTML style
attribute to apply styles, the declarations are applied only to the element. These are, in effect, “scoped” declarations, which override any declarations applied from your stylesheet or a <style>
tag.
To override inline declarations in your stylesheet, you’ll need to add an !important
to the declaration, shifting it into a higher-priority origin. If the inline styles are marked important, then nothing can override them.
The second part of specificity is determined by the selectors. Different types of selectors have different specificities. An ID selector has a higher specificity than a class selector. Similarly, a class selector has a higher specificity than a tag selector (also called a type selector).
The exact rules of specificity are:
For example:
/* (1) four tags */
html body header h1 {
color: blue;
}
/* (2) three tags and one class */
body header.page-header h1 {
color: orange;
}
/* (3) two classes */
.page-header .title {
color: green;
}
/* (4) one ID */
#page-title {
color: red;
}
The most specific selector here is (4), with one ID. The next specific is (3), with two class names. Selector (3) has a higher specificity than selector (2), despite its length: two classes are more specific than one class. The least specific selector is (1), even it has four element types (tag names).
Pseudo-class selectors (e.g.,
:hover
) and attribute selectors (e.g.,[type="input"]
) each have the same specific as a class selector. The universal selector (*
) and combinators (>
,+
, and~
) have no effect on specificity.
If you add a declaration to your CSS and it seems have no effect, often it’s because a more specific rule is overriding it.
A common way to indicate specificity is in a number form, often with commas between each number. For example, “1,2,2” indicates a specificity of one ID, two classes, and two tags. IDs having the highest priority are listed first, followed by classes, then tags.
The selector #page-header #page-title
has two IDs, no classes, and no tags. We can say this selector has a specificity of “2,0,0”. The ul li
, with two tags but no IDs or classes, has a specificity of “0,0,2”.
It now becomes a matter of comparing the numbers to determine which selector is more specific. A specificity of “1,0,0” takes precedence over a specificity of “0,2,2” and ever over “0,10,0”.
Occasionally, people use a four-number notation with a 0 or 1 in the most significant digit to represent whether a declaration is applied via inline styles. In this case, an inline style has a specificity of “1,0,0,0”. This would override styles applied via selectors, which could be indicated as having specificities of “0,1,2,0” or something similar.
To raise the specificity, the quickest fix is to add an !important
to the declaration you want to favour. This works because the !important
annotation raises the declaration to a higher priority origin. Sure, it’s easy, but it’s also a naive fix and not recommended.
Instead of raising the specificity of the selector, we can also lower the specificity of the selector to get the same result. It is generally best to keep specificity low when you can, so when you need to override something, your options are open.
The third and final step to resolving the cascade is source order. If the origin and the specificity are the same, then the declaration that appears later in the stylesheet, or appears in a stylesheet included later on the page, takes precedence. This means you can manipulate the source order to style your featured link. If you make the two conflicting selectors equal in specificity, then whichever appears last wins.
For styling links (<a>
tags), it should go in a certain order. That’s because source order affects the cascade. This listing shows styles for links on a page in the “corret” order, the so-called “LoVe/HAte” order:
a:link {
color: blue;
text-decoration: none;
}
a:visited {
color: purple;
}
a:hover {
text-decoration: underline;
}
a:active {
color: red;
}
The cascade is the reason this order matters: given the same specificity, later styles override earlier styles. If two or more of these states are true of one element at the same time, the last one override the others. If the user hovers over a visited link, the hover styles take precedence. If the user activates the link (i.e., clicks it) while hovering over it, the active styles take precedence.
The browser follows these three steps — origin, specificity, and source order to resolve every property for every element on the page. A declaration that “wins” the cascade is called a cascaded value. There’s at most one cascaded value per property per element.
If an element has no cascaded value for a given property, it may inherit one from an ancestor element. It’s common to apply a font-family
to the <body>
element. All the ancestor elements within will then inherit this font.
Note that NOT all properties are inherited, however. By default, only certain ones are. In general, these are the properties you’ll want to be inherited. They are primarily properties pertaining to text: color
, font
, font-family
, font-size
, font-weight
, font-variant
, font-style
, line-height
, letter-spacing
, text-align
, text-indent
, text-transform
, white-space
, and word-spacing
.
A few others inherit as well, such as the list properties: list-style
, list-style-type
, list-style-position
, and list-style-image
. The table border properties, border-collapse
and border-spacing
, are also inherited.
Above is not quite a comprehensive list, but very nearly.
There are two special values that you can apply to any property to help manipulate the cascade: inherit
and initial
.
Using the inherit
keyword, you can override another value with this, and it will cause the element to inherit that value from its parent.
Sometimes you’ll find you have styles applied to an element that you want to undo. You can do this by specifying the keyword initial
. Every CSS property has an initial, or default, value. If you assign the value initial
to that property, then it effectively resets to its default value. The benefit of this is you don’t have to think about it as much. If you want to remove a border from an element, set border: initial
. If you want to restore an element to its default width, set width: initial
.
Declaring
display: initial
is equivalent todisplay: inline
. It won’t evaluate todisplay: block
regardless of what type of element you apply it to. That’s becauseinitial
resets to the initial value for the property, not the element.
Frank Lin
Web Notes
2016.08.20
Liquid is a simple template language that Jekyll uses to process pages for your site. With Liquid you can output complex contents without additional plugins.
JavaScript Notes
2018.12.17
JavaScript is a very function-oriented language. As we know, functions are first class objects and can be easily assigned to variables, passed as arguments, returned from another function invocation, or stored into data structures. A function can access variable outside of it. But what happens when an outer variable changes? Does a function get the most recent value or the one that existed when the function was created? Also, what happens when a function invoked in another place - does it get access to the outer variables of the new place?
Tutorials
2020.01.09
IKEv2, or Internet Key Exchange v2, is a protocol that allows for direct IPSec tunnelling between networks. It is developed by Microsoft and Cisco (primarily) for mobile users, and introduced as an updated version of IKEv1 in 2005. The IKEv2 MOBIKE (Mobility and Multihoming) protocol allows the client to main secure connection despite network switches, such as when leaving a WiFi area for a mobile data area. IKEv2 works on most platforms, and natively supported on some platforms (OS X 10.11+, iOS 9.1+, and Windows 10) with no additional applications necessary.