Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
This article is a summary of learning and using Stylus, an expressive, dynamic, and robust CSS preprocessor.
Characteristics of the
Colon optional optional comma, semicolon optional, optional brackets, variables, interpolation, mixed writing, and arithmetic, casts, dynamic import, conditions, choice of iteration, nested, parent reference, variable, function calls, lexical scope, built-in functions, internal language function, optional compression, image inline optional, executable Stylus, robust error reporting, single – and multi-line comments, CSS literals, character escapes, TextMate bindings, and more.
use
Global installation
$ npm install stylus -g
Copy the code
Compiling a single file
stylus demo.styl
Copy the code
Compile the entire folder
Current folder under stylusCopy the code
Dynamically listen to the entire folder
stylus -w
Copy the code
Dynamically listen to the entire folder and compress
stylus -w --compress
Copy the code
The basic grammar
The selector
indentation
The Stylus syntax is based on indentation; Spaces have significant meaning and use indentation and indentation instead of curly braces {and}.
body
color white
Copy the code
The above code corresponds to:
body {
color: #fff;
}
Copy the code
Can be separated by a colon to make reading easier:
body
color: white
Copy the code
A set of rules
Stylus, like CSS, allows you to define attributes for multiple selectors simultaneously using commas.
textarea.input
border 1px solid #eee
Copy the code
Using a new line has the same effect:
textarea
input
border 1px solid #eee
Copy the code
Is equal to:
textarea.input {
border: 1px solid #eee;
}
Copy the code
The only exception to this rule is selectors that look like attributes. For example, foo bar baz below might be an attribute or a selector.
foo bar baz
> input
border 1px solid
Copy the code
To solve this problem, put a comma at the end:
foo bar baz,
form input,
> a
border 1px solid
Copy the code
The parent reference
The character & points to the parent selector. In this example, two selectors (textarea and input) change the color value on the :hover pseudo-class selector
textarea
input
color #A7A7A7
&:hover
color # 000
Copy the code
Is equal to:
textarea.input {
color: #a7a7a7;
}
textarea:hover.input:hover {
color: # 000;
}
Copy the code
In this example, Internet Explorer uses parent references and mixed writing to achieve a 2px border.
box-shadow()
-webkit-box-shadow arguments
-moz-box-shadow arguments
box-shadow arguments
html.ie8 &,
html.ie7 &,
html.ie6 &
border 2px solid arguments[length(arguments) - 1]
body
#login
box-shadow 1px 1px 3px #eee
Copy the code
Results:
body #login {
-webkit-box-shadow: 1px 1px 3px #eee;
-moz-box-shadow: 1px 1px 3px #eee;
box-shadow: 1px 1px 3px #eee;
}
html.ie8 body #login.html.ie7 body #login.html.ie6 body #login {
border: 2px solid #eee;
}
Copy the code
disambiguation
A padding-n-like expression may be interpreted as either a subtraction operation or a unary minus attribute. To avoid this ambiguity, wrap the expression in parentheses:
pad(n)
padding (- n)
body
pad(5px)
Copy the code
Results:
body {
padding: -5px;
}
Copy the code
However, this is only true in a function (because the function also acts as a mix or callback with the return value). For example, the following is OK:
body
padding -5px
Copy the code
Unquote () can handle attribute values that Stylus cannot:
filter unquote('progid:DXImageTransform.Microsoft.BasicImage(rotation=1)')
Copy the code
Results:
filter progid:DXImageTransform.Microsoft.BasicImage(rotation=1)
Copy the code
variable
variable
We can specify the expression as a variable and then use it throughout the style:
font-size = 14px
body
font font-size Arial, sans-seri
Copy the code
Results:
body {
font: 14px Arial, sans-serif;
}
Copy the code
Variables can even form a list of expressions:
font-size = 14px
font = font-size "Lucida Grande", Arial
body
font font sans-serif
Copy the code
Results:
body {
font: 14px "Lucida Grande", Arial sans-serif;
}
Copy the code
Identifiers (variable names, functions, etc.) may also include the $character. Such as:
$font-size = 14px
body {
font: $font-size sans-serif;
}
Copy the code
Attributes to find
Stylus has another cool unique feature that allows you to define reference properties without assigning values to variables. Here is a good example of an element centered horizontally and vertically (typically using percentages and margin negative values), as follows:
#logo
position: absolute
top: 50%
left: 50%
width: w = 150px
height: h = 80px
margin-left: -(w / 2)
margin-top: -(h / 2)
Copy the code
Instead of using the variables w and h here, we simply prefix the @ character before the attribute name to access the value corresponding to that attribute name:
#logo
position: absolute
top: 50%
left: 50%
width: 150px
height: 80px
margin-left: -(@width / 2)
margin-top: -(@height / 2)
Copy the code
In addition, use cases define attributes conditionally based on other attributes. In the following example, we specify a z-index value of 1 by default, but only if z-index is not specified before:
position(a)
position: arguments
z-index: 1 unless @z-index
#logo
z-index: 20
position: absolute
#logo2
position: absolute
Copy the code
The property bubbles up the stack until it is found, or returns null if the property is undecided. In this example, the @color value is blue.
body
color: red
ul
li
color: blue
a
background-color: @color
Copy the code
The interpolation
The interpolation
Stylus supports inserting values by enclosing expressions with {} characters that become part of the identifier. For example, -webkit-{‘border’ + ‘-radius’} is equivalent to -webkit-border-radius. A good example is the private prefix attribute extension:
vendor(prop, args)
-webkit-{prop} args
-moz-{prop} args
{prop} args
border-radius(a)
vendor('border-radius', arguments)
box-shadow(a)
vendor('box-shadow', arguments)
button
border-radius 1px 2px / 3px 4px
Copy the code
Results:
button {
-webkit-border-radius: 1px 2px / 3px 4px;
-moz-border-radius: 1px 2px / 3px 4px;
border-radius: 1px 2px / 3px 4px;
}
Copy the code
Selector interpolation
Interpolation can also work on selectors. For example, we could specify the height of the first five rows of the table as follows:
table
for row in 1 2 3 4 5
tr:nth-child({row})
height: 10px * row
Copy the code
Results:
table tr:nth-child(1) {
height: 10px;
}
table tr:nth-child(2) {
height: 20px;
}
table tr:nth-child(3) {
height: 30px;
}
table tr:nth-child(4) {
height: 40px;
}
table tr:nth-child(5) {
height: 50px;
}
Copy the code
The operator
Operator priority
The following table lists the operators’ priorities, from highest to lowest:
[]! ~ + - is defined ** * / % + - ... . The < = > = < >in== is ! = is not isnt isa
&& and || or
?:
= := ?= += -= *= /= %=
not
if unless
Copy the code
Unary operator
The following unary operators are available,! , not, -, + and ~.
!0 // => true!!!!!0 // => false
!1 // => false!!!!!5px // => true
-5px // => -5px
--5px // => 5px
not true // => false
not not true // => true
Copy the code
The logical operator NOT has a lower priority, so the following example can be replaced:
a = 0
b = 1
!a and !b // => false: (! a) and (! b)
Copy the code
To use:
not a or b // => false; not (a or b)
Copy the code
Binary operator
The subscript operator [] allows us to get the inner value of an expression by index. Parenthesis expressions can act as tuples (e.g. (15px 5px), (1, 2, 3)).
The following example uses error-handling tuples (and demonstrates the versatility of the structure) :
add(a, b)
if a is a 'unit' and b is a 'unit'
a + b
else
(error 'A and B must be units! ')
body
padding add(1.'5') // => padding: error "A and B have to be units.";
padding add(1.'5') [0] // => padding: error;
padding add(1.'5') [0] == error // => padding: true;
padding add(1.'5') [1] // => padding: "A and B have to be units.";
Copy the code
Here’s a more complicated example. Now, we call the built-in error() function, which returns an error message when the identifier (the first value) equals error.
if (val = add(1.'5'))[0] == error
error(val[1])
Copy the code
The scope of.
.
Also provides the contain boundary operator (..) And range operators (…) , see the following expression:
1.5 // => 1 2 3 4 5
1.5 // => 1 2 3 4
Copy the code
Add:+
-
Binary multiplicative operations convert units, or use default literal values. For example, 5s-2px is 3s.
15px - 5px // => 10px
5 - 2 / / = > 3
5in - 50mm / / = > 3.031 in
5s - 1000ms // => 4s
20mm + 4in / / = > 121.6 mm
"foo " + "bar" // => "foo bar"
"num " + 15 // => "num 15"
Copy the code
Battles:/
*
%
2000ms + (1s * 2) // => 4000ms
5s / 2 / / = > 2.5 s
4 % 2 / / = > 0
Copy the code
When using/in attribute values, you must enclose parentheses. Otherwise/is treated literally (CSS line-height is supported).
font: 14px/1.5; // However, this is equivalent to 14px ÷ 1.5:
font: (14px/1.5); // Only the/operator requires this.
Copy the code
Index: * *
Index operators:
2 ** 8 / / = > 256
Copy the code
Operation of equality and relation:= =
! =
> =
< =
>
<
The equality operator can be used to equate units, colors, strings, and even identifiers. This is such a powerful concept that even arbitrary identifiers (like Wahoo) can be used as atoms. The function can return yes and no instead of true and false (although it is not recommended).
5= =5 // => true
10 > 5 // => true
#fff= =#fff // => true
true == false // => false
wahoo == yay // => false
wahoo == wahoo // => true
"test"= ="test" // => true
true is true // => true
'hey' is not 'bye' // => true
'hey' isnt 'bye' // => true
(foo bar) == (foo bar) // => true
(1 2 3) = = (1 2 3) // => true
(1 2 3) = = (1 1 3) // => false
Copy the code
Only exact values are matched, for example, 0 == false and null == False return false.
Alias:
= =
: is! =
: is not! =
: isnt
True and false
Stylus is true for almost everything, including suffixed units, even 0%, 0px, etc. However, 0 itself is false in arithmetic, and expressions (or “lists”) of length greater than 1 are considered true.
True examples:
0%
0px
1px
-1
-1px
hey
'hey'
(0 0 0)
(' ' ' ')
Copy the code
False examples:
0
null
false
Copy the code
Logical operators:&&
||
和 or
Logical operators && and | | alias is and/or. They have the same priority.
5 && 3 / / = > 3
0 || 5 / / = > 5
0 && 5 / / = > 0
#fff is a 'rgba' and 15 is a 'unit' // => true
Copy the code
Presence operator:in
Check to see if the left-hand side is in the right-hand expression. A simple example:
nums = 1 2 3
1 in nums // => true
5 in nums // => false
Copy the code
Some undefined identifiers:
words = foo bar baz
bar in words // => true
HEY in words // => false
Copy the code
Tuples also apply:
vals = (error 'one') (error 'two')
error in vals // => false
(error 'one') in vals // => true
(error 'two') in vals // => true
(error 'something') in vals // => false
Copy the code
Examples of mixed writing:
pad(types = padding, n = 5px)
if padding in types
padding n
if margin in types
margin n
body
pad()
body
pad(margin)
body
pad(padding margin, 10px)
Copy the code
Corresponds to:
body {
padding: 5px;
}
body {
margin: 5px;
}
body {
padding: 10px;
margin: 10px;
}
Copy the code
Conditional assignment:? =
: =
Conditional assignment operator? = (alias? 🙂 makes it necessary to define variables without destroying old values (if any). This operator can be extended to binary operations with the ternary is defined. For example, the following functions are the same:
color := white
color? = whitecolor = color is defined ? color : white
Copy the code
If we use the equal sign =, we simply assign.
color = white
color = black
color // => black
Copy the code
But when used? =, the second assignment is invalid:
color = white
color? = blackcolor // => white
Copy the code
Example check:is a
The Stylus provides a binary operator called is A for type checking.
15 is a 'unit' // => true
#fff is a 'rgba' // => true
15 is a 'rgba' // => false
Copy the code
Alternatively, we can use the type() built-in function.
type(#fff)= ='rgba' // => true
Copy the code
Note: color is the only special case, true when the left is an RGBA or HSLA node.
Variable definition:is defined
This pseudo-binary operator is empty on the right and computes on the left. Used to check whether a variable has been assigned a value.
foo is defined // => false
foo = 15px
foo is defined // => true
#fff is defined // => 'invalid "is defined" check on non-variable #fff'
Copy the code
Alternatively, we can do this active lookup using the built-in lookup(name) method.
name = 'blue'
lookup('light-' + name) // => null
light-blue = #80e2e9
lookup('light-' + name) // => #80e2e9
Copy the code
This operator is necessary because an undefined identifier is still true. Such as:
body
if ohnoes
padding 5px
Copy the code
When undefined, the following CSS is generated:
body {
padding: 5px;
}
Copy the code
Obviously, this is not what we want, so it’s safe to write:
body
if ohnoes is defined
padding 5px
Copy the code
Three yuan
Ternary operators work just as they do in most languages. Operators (conditional expressions, true expressions, and false expressions) for three operation objects.
num = 15
num ? unit(num, 'px') : 20px // => 15px
Copy the code
casting
Instead of the terse built-in unit() function, the syntax (expr) unit can be used to enforce suffixes.
body
n = 5
foo: (n)em
foo: (n)%
foo: (n + 5)%
foo: (n * 5)px
foo: unit(n + 5.The '%')
foo: unit(5 + 180 / 2, deg)
Copy the code
Color operation
Color manipulation provides a concise, expressive way to change its composition. For example, we can apply each RGB:
#0e0 + #0e0 // => #0f0
Copy the code
Another example is adjusting color brightness by increasing or decreasing the hundred points. Bright color, plus; Dark, minus.
# 888 + 50% // => #c3c3c3
# 888 - 50% / / = > # 444
Copy the code
We can also adjust the hue by adding or subtracting the hue. For example, red increases by 65deg and becomes yellow.
#f00 + 50deg // => #ffd500
Copy the code
Values are properly fixed. For example, we can “rotate” the hue by 180 degrees, and if the current value is 320deg, it will become 140deg.
We may also adjust several values (including alpha) at once, by using RGB (), RGBA (), HSL (), or HSLA ():
#f00 - rgba(100.0.0.0.5) / / = > rgba (155,0,0,0.5)
Copy the code
Formatted string
The formatted string % can be used to generate literal values by passing arguments to the built-in s() method.
'X::Microsoft::Crap(%s)' % #fc0 // => X::Microsoft::Crap(#fc0)
Copy the code
Multiple values need to be enclosed:
'-webkit-gradient(%s, %s, %s)' % (linear (0 0) (0 100%)) // => -webkit-gradient(linear, 0 0, 0 100%)
Copy the code
Mix writing
Mixed with
Blending is the same as the method of function definition, but the application is quite different. For example, here is the border-radius(n) method defined, which is called as a mixin (i.e., as a state call, not an expression). When called in the border-radius() selector, the attribute is extended and copied in the selector.
border-radius(n)
-webkit-border-radius n
-moz-border-radius n
border-radius n
form input[type=button]
border-radius(5px)
Copy the code
Compiled into:
form input[type=button] {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
Copy the code
With mixin writing, parentheses can be ignored entirely.
border-radius(n)
-webkit-border-radius n
-moz-border-radius n
border-radius n
form input[type=button]
border-radius 5px
Copy the code
Notice that we mixed the border-radius writing as a property, not a recursive function call.
Further, we can use arguments as a local variable to pass expressions that can contain multiple values.
border-radius(a)
-webkit-border-radius arguments
-moz-border-radius arguments
border-radius arguments
Copy the code
Now, we can pass values like this: border-radius 1px 2px / 3px 4px Another nice application is specific private prefix support — IE transparency for example:
support-for-ie ? = trueopacity(n)
opacity n
if support-for-ie
filter unquote('progid:DXImageTransform.Microsoft.Alpha(Opacity=' + round(n * 100) + ') ')
#logo
&:hover
opacity 0.5
Copy the code
Apply colours to a drawing as follows:
#logo:hover {
opacity: 0.5;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50);
}
Copy the code
The parent reference
Mixed writing can take advantage of the parent reference character &, inheriting the father’s work rather than building its own nest.
For example, we want to create a stripe table with stripe(even, odd). Both even and odd provide default color values, and each line also specifies background-color. We can reference tr with & in tr nesting to provide even color.
stripe(even = #fff, odd = #eee)
tr
background-color odd
&.even
&:nth-child(even)
background-color even
Copy the code
Then, use mixed writing as follows:
table
stripe()
td
padding 4px 10px
table#users
stripe(# 303030.# 494848)
td
color white
Copy the code
In addition, stripe() is defined without a parent reference:
stripe(even = #fff, odd = #eee)
tr
background-color odd
tr.even
tr:nth-child(even)
background-color even
Copy the code
If you like, you can call stripe() as an attribute.
stripe #fff # 000
Copy the code
Mixed writing of mixed writing
Mixed writing can take advantage of other mixed writing, based on their own properties and selectors. For example, let’s create inline comma-list() (via inline-list()) and comma-separated unordered lists.
inline-list(a)
li
display inline
comma-list(a)
inline-list()
li
&:after
content ', '
&:last-child:after
content ' '
ul
comma-list()
Copy the code
Render:
ul li:after {
content: ",";
}
ul li:last-child:after {
content: "";
}
ul li {
display: inline;
}
Copy the code
function
function
Stylus’s power lies in its built-in language function definitions. The definition is the same as mixins; It can return a value.
The return value
For example, the method of adding two values
add(a, b)
a + b
body
padding add(10px.5)
Copy the code
Render:
body {
padding: 15px;
}
Copy the code
The default parameters
In Stylus, you can set default parameters. Such as:
add(a, b = a)
a + b
add(10.5) / / = > 15
add(10) / / = > 20
Copy the code
Since the argument defaults to assignment, we can use a function call as the default:
add(a, b = unit(a, px))
a + b
Copy the code
The body of the function
You can take the simple add() method one step further. Change the units to PX with built-in unit(), because assignments are made to each argument, so unit conversions can be ignored.
add(a, b = a)
a = unit(a, px)
b = unit(b, px)
a + b
add(15%.10deg) / / = > 25
Copy the code
Multiple return values
Functions in Stylus can return multiple values, just as you assign multiple values to variables. For example, here is a valid assignment:
sizes = 15px 10px
sizes[0] // => 15px
Copy the code
Similarly, we can return multiple values in a function:
sizes(a)
15px 10px
sizes(a)[0] // => 15px
Copy the code
The small exception is when the return value is an identifier. For example, the following looks like an attribute assigned to the Stylus (because there is no operator).
swap(a, b)
b a
Copy the code
To avoid ambiguity, use parentheses, or the return keyword.
swap(a, b)
(b a)
swap(a, b)
return b a
Copy the code
conditions
Suppose we want to create a function called stringish() that determines whether the argument is a string. Check if val is a string or indent (like a character). Use yes and no instead of true and false as follows.
stringish(val)
if val is a 'string' or val is a 'ident'
yes
else
no
Copy the code
Use:
stringish('yay') == yes // => true
stringish(yay) == yes // => true
stringish(0) == no // => true
Copy the code
Note: Yes and no are not Boolean values.
Another example:
compare(a, b)
if a > b
higher
else if a < b
lower
else
equal
/ / use:
compare(5.2) // => higher
compare(1.5) // => lower
compare(10.10) // => equal
Copy the code
The alias
Give the function a different name, such as add() above add alias plus(), as follows:
plus = add
plus(1.2) / / = > 3
Copy the code
Variable function
You can pass a function as a variable to a new function. For example, invoke() accepts functions as arguments, so you can pass Add () as well as sub().
invoke(a, b, fn)
fn(a, b)
add(a, b)
a + b
body
padding invoke(5.10, add)
padding invoke(5.10, sub)
Copy the code
Results:
body {
padding: 15;
padding: -5;
}
Copy the code
parameter
Arguments are local variables that all function bodies have, containing all arguments passed.
Such as:
sum(a)
n = 0
for num in arguments
n = n + num
sum(1.2.3.4.5) / / = > 15
Copy the code
Hash sample
Next, we define the get(hash, key) method, which returns the key value or null. We iterate over each key value pair and return the corresponding value if the key value matches.
get(hash, key)
return pair[1] if pair[0] == key for pair in hash
Copy the code
The following example demonstrates that Stylus expressions, which look like language functions, have greater flexibility.
hash = (one 1) (two 2) (three 3)
get(hash, two) / / = > 2
get(hash, three) / / = > 3
get(hash, something) // => null
Copy the code
Keyword parameter
Keyword parameter
Stylus supports keyword parameters, or kwargs. Allows you to reference parameters according to the related parameter name.
The following examples are functionally the same. However, we can place keyword arguments anywhere in the list. The remaining untyped parameters will apply to parameters that have not yet been satisfied.
body {
color: rgba(255.200.100.0.5);
color: rgba(red: 255, green: 200, blue: 100, alpha: 0.5);
color: rgba(alpha: 0.5, blue: 100, red: 255.200);
color: rgba(alpha: 0.5, blue: 100.255.200);
}
Copy the code
Is equal to:
body {
color: rgba(255.200.100.0.5);
color: rgba(255.200.100.0.5);
color: rgba(255.200.100.0.5);
color: rgba(255.200.100.0.5);
}
Copy the code
To view arguments accepted in a function or mixed writing, use the p() method.
p(rgba)
Copy the code
Generation:
inspect: rgba(red, green, blue, alpha)
Copy the code
annotation
annotation
Stylus supports three types of annotations, single-line annotations, multi-line annotations, and multi-line buffered annotations.
Single-line comments
Like JavaScript, double slashes are not output in CSS.
// I am a comment!
body
padding 5px // padding
Copy the code
Multiline comment
Multi-line comments look a bit like regular CSS comments and are only printed if the COMPRESS option is not enabled.
/* * The given value is combined with */
Copy the code
Multi-line buffer comments
Similar to multi-line comments, except that at the beginning, it is /*! This is equivalent to telling the Stylus to ignore the direct output when it compresses.
/ *! * The given numeric combination */
Copy the code
To be continued… , please continue to read Stylus Learning and Using (Ii)