Saturday, August 8, 2009
Javascript: Static Methods and Variables
Applying the lesson of scope and closures from earlier in the chapter can lead to a way to
create static members, which can be both private and publicly accessible. Most methods
and attributes interact with an instance of a class; static members interact with the class
itself. Another way of putting it is to say that static members operate on the class-level instead
of the instance-level; there is only one copy of each static member. As you will see later in
this section, static members are called directly off of the class object.
Here is the Book class with static attributes and methods:
var Book = (function() {
// Private static attributes.
var numOfBooks = 0;
// Private static method.
function checkIsbn(isbn) {
...
}
// Return the constructor.
return function(newIsbn, newTitle, newAuthor) { // implements Publication
// Private attributes.
var isbn, title, author;
// Privileged methods.
this.getIsbn = function() {
return isbn;
};
this.setIsbn = function(newIsbn) {
if(!checkIsbn(newIsbn)) throw new Error('Book: Invalid ISBN.');
isbn = newIsbn;
};
this.getTitle = function() {
return title;
};
this.setTitle = function(newTitle) {
title = newTitle || 'No title specified';
};
this.getAuthor = function() {
return author;
};
this.setAuthor = function(newAuthor) {
author = newAuthor || 'No author specified';
};
// Constructor code.
numOfBooks++; // Keep track of how many Books have been instantiated
// with the private static attribute.
if(numOfBooks > 50) throw new Error('Book: Only 50 instances of Book can be '
+ 'created.');
this.setIsbn(newIsbn);
this.setTitle(newTitle);
this.setAuthor(newAuthor);
}
})();
// Public static method.
Book.convertToTitleCase = function(inputString) {
...
};
// Public, non-privileged methods.
Book.prototype = {
display: function() {
...
}
};
This is similar to the class created earlier in the chapter in the “Private Members Through
Closures” section, with a couple of key differences. Private and privileged members are still
declared within the constructor, using var and this respectively, but the constructor is changed
from a normal function to a nested function that gets returned to the variable Book. This makes
it possible to create a closure where you can declare private static members. The empty parentheses
after the function declaration are extremely important. They serve to execute that
function immediately, as soon as the code is loaded (not when the Book constructor is called).
The result of that execution is another function, which is returned and set to be the Book constructor.
When Book is instantiated, this inner function is what gets called; the outer function is
used only to create a closure, within which you can put private static members.
In this example, the checkIsbn method is static because there is no point in creating a new
copy of it for each instance of Book. There is also a static attribute called numOfBooks, which allows
you to keep track of how many times the Book constructor has been called. In this example, we
use that attribute to limit the constructor to creating only 50 instances.
These private static members can be accessed from within the constructor, which means
that any private or privileged function has access to them. They have a distinct advantage over
these other methods in that they are only stored in memory once. Since they are declared outside
of the constructor, they do not have access to any of the private attributes, and as such, are
not privileged; private methods can call private static methods, but not the other way around.
A rule of thumb for deciding whether a private method should be static is to see whether it
needs to access any of the instance data. If it does not need access, making the method static
is more efficient (in terms of memory use) because only a copy is ever created.
Public static members are much easier to create. They are simply created directly off of
the constructor, as with the previous method convertToTitleCase. This means you are essentially
using the constructor as a namespace.
■Note In JavaScript, everything except for variables of the three primitive types is an object (and even
those primitives are automatically wrapped by objects when needed). This means that functions are also
objects. Since objects are essentially hash tables, you can add members at any time. The end result of this is
that functions can have attributes and methods just like any other object, and they can be added whenever
you want.
All public static methods could just as easily be declared as separate functions, but it is useful
to bundle related behaviors together in one place. They are useful for tasks that are related to
the class as a whole and not to any particular instance of it. They don’t directly depend on any of
the data contained within the instances.
Another Example:
var StaticTest = (function()
{
var count = 0; //Static Variable
return function() { //Constructor
this.incrementCount = function() { //public privileged function
count++;
};
this.printCount = function() { //public privileged function
alert("The count is: " + count);
};
}
})();
//Static Method
StaticTest.printCount = function() {
alert("The count is not accessible in static method [printCount()]");
};
new StaticTest().incrementCount(); //increments count to 1
new StaticTest().printCount(); //prints count as 1
new StaticTest().incrementCount(); //increments count to 2
new StaticTest().printCount(); //prints count as 1
StaticTest.printCount(); //prints The count is not accessible in static method [printCount()]
Source: Pro Javascript Design Patterns
Friday, August 7, 2009
Javascript: Private Members through Closures
A closure seems to be a perfect fit because it allows you to create variables that are accessible
only to certain functions and are preserved in between those function calls. To create private
attributes, you define variables in the scope of your constructor function. These attributes will
be accessible to all functions defined within this scope, including privileged methods:
var Book = function(newIsbn, newTitle, newAuthor) { // implements Publication
// Private attributes.
var isbn, title, author;
// Private method.
function checkIsbn(isbn) {
...
}
// Privileged methods.
this.getIsbn = function() {
return isbn;
};
this.setIsbn = function(newIsbn) {
if(!checkIsbn(newIsbn)) throw new Error('Book: Invalid ISBN.');
isbn = newIsbn;
};
this.getTitle = function() {
return title;
};
this.setTitle = function(newTitle) {
title = newTitle || 'No title specified';
};
this.getAuthor = function() {
return author;
};
this.setAuthor = function(newAuthor) {
author = newAuthor || 'No author specified';
};
// Constructor code.
this.setIsbn(newIsbn);
this.setTitle(newTitle);
this.setAuthor(newAuthor);
};
// Public, non-privileged methods.
Book.prototype = {
display: function() {
...
}
};
So how is this different from the other patterns we’ve covered so far? In the other Book
examples, we always created and referred to the attributes using the this keyword. In this
example, we declared these variables using var. That means they will only exist within the Book
constructor. We also declare the checkIsbn function in the same way, making it a private method.
Any method that needs to access these variables and functions need only be declared
within Book. These are called privileged methods because they are public but have access to
private attributes and methods. The this keyword is used in front of these privileged functions
to make them publicly accessible. Because these methods are defined within the Book constructor’s
scope, they can access the private attributes. They are not referred to using this because
they aren’t public. All of the accessor and mutator methods have been changed to refer to the
attributes directly, without this.
Any public method that does not need direct access to private attributes can be declared
normally in the Book.prototype. An example of one of these methods is display; it doesn’t
need direct access to any of the private attributes because it can just call getIsbn or getTitle.
It’s a good idea to make a method privileged only if it needs direct access to the private members.
Having too many privileged methods can cause memory problems because new copies
of all privileged methods are created for each instance.
With this pattern, you can create objects that have true private attributes. It is impossible
for other programmers to create an instance of Book and directly access any of the data. You
can tightly control what gets set because they are forced to go through the mutator methods.
This pattern solves all of the problems with the other patterns, but it introduces a few drawbacks
of its own. In the fully exposed object pattern, all methods are created off of the prototype,
which means there is only one copy of each in memory, no matter how many instances you create.
In this pattern, you create a new copy of every private and privileged method each time a new
object is instantiated. This has the potential to use more memory than the other patterns, so it
should only be used when you require true private members. This pattern is also hard to subclass.
The new inherited class will not have access to any of the superclass’s private attributes or methods.
It is said that “inheritance breaks encapsulation” because in most languages, the subclass has
access to all of the private attributes and methods of the superclass. In JavaScript, this is not the
case. If you are creating a class that might be subclassed later, it is best to stick to one of the fully
exposed patterns.
Summary
1) To declare private variables dont use this keyword, instead use var with in the constructor.
2) The same applies to the private functions as well like checkIsbn() function above.
3) To declare public privileged functions [functions which are public and which can access private variables] use this keyword and define it with in the constructor like setIsbn(), getIsbn() api's above.
4) To declare public non-privileged functions [functions which are public and which cannot access private variables] use prototype to define.
Source:
Pro Javascript Design Patterns
Interfaces in Javascript
// Interfaces.
var Composite = new Interface('Composite', ['add', 'remove', 'getChild']);
var FormItem = new Interface('FormItem', ['save']);
// CompositeForm class
var CompositeForm = function(id, method, action) { // implements Composite, FormItem
...
};
...
function addForm(formInstance) {
Interface.ensureImplements(formInstance, Composite, FormItem);
// This function will throw an error if a required method is not implemented,
// halting execution of the function.
// All code beneath this line will be executed only if the checks pass.
...
}
Interface.ensureImplements provides a strict check. If a problem is found, an error will be
thrown, which can either be caught and handled or allowed to halt execution. Either way, the
programmer will know immediately that there is a problem and where to go to fix it.
The Interface Class
The following is the Interface class that we use throughout the book:
// Constructor.
var Interface = function(name, methods) {
if(arguments.length != 2) {
throw new Error("Interface constructor called with " + arguments.length +
"arguments, but expected exactly 2.");
}
this.name = name;
this.methods = [];
for(var i = 0, len = methods.length; i < len; i++) {
if(typeof methods[i] !== 'string') {
throw new Error("Interface constructor expects method names to be "
+ "passed in as a string.");
}
this.methods.push(methods[i]);
}
};
// Static class method.
Interface.ensureImplements = function(object) {
if(arguments.length < 2) {
throw new Error("Function Interface.ensureImplements called with " +
arguments.length + "arguments, but expected at least 2.");
}
for(var i = 1, len = arguments.length; i < len; i++) {
var interface = arguments[i];
if(interface.constructor !== Interface) {
throw new Error("Function Interface.ensureImplements expects arguments"
+ "two and above to be instances of Interface.");
}
for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) {
var method = interface.methods[j];
if(!object[method] || typeof object[method] !== 'function') {
throw new Error("Function Interface.ensureImplements: object "
+ "does not implement the " + interface.name
+ " interface. Method " + method + " was not found.");
}
}
}
};
As you can see, it is very strict about the arguments given to each method and will throw
an error if any check doesn’t pass. This is done intentionally, so that if you receive no errors,
you can be certain the interface is correctly declared and implemented.
The Flexibility of JavaScript
One of the most powerful features of the language is its flexibility. As a JavaScript programmer,
you can make your programs as simple or as complex as you wish them to be. The language
also allows several different programming styles. You can write your code in the functional style
or in the slightly more complex object-oriented style. It also lets you write relatively complex
programs without knowing anything at all about functional or object-oriented programming;
you can be productive in this language just by writing simple functions. This may be one of the
reasons that some people see JavaScript as a toy, but we see it as a good thing. It allows programmers
to accomplish useful tasks with a very small, easy-to-learn subset of the language. It also
means that JavaScript scales up as you become amore advanced programmer.
JavaScript allows you to emulate patterns and idioms found in other languages. It even
creates a few of its own. It provides all the same object-oriented features as the more traditional
server-side languages.
Let’s take a quick look at a few different ways you can organize code to accomplish one
task: starting and stopping an animation. It’s OK if you don’t understand these examples; all of
the patterns and techniques we use here are explained throughout the book. For now, you can
view this section as a practical example of the different ways a task can be accomplished in
JavaScript.
If you’re coming from a procedural background, you might just do the following:
/* Start and stop animations using functions. */
function startAnimation() {
...
}
function stopAnimation() {
...
}
This approach is very simple, but it doesn’t allow you to create animation objects, which
can store state and have methods that act only on this internal state. This next piece of code
defines a class that lets you create such objects:
/* Anim class. */
var Anim = function() {
...
};
Anim.prototype.start = function() {
...
};
Anim.prototype.stop = function() {
...
};
/* Usage. */
var myAnim = new Anim();
myAnim.start();
...
myAnim.stop();
This defines a new class called Anim and assigns two methods to the class’s prototype
property. We cover this technique in detail in Chapter 3. If you prefer to create classes encapsulated
in one declaration, you might instead write the following:
/* Anim class, with a slightly different syntax for declaring methods. */
var Anim = function() {
...
};
Anim.prototype = {
start: function() {
...
},
stop: function() {
...
}
};
This may look a little more familiar to classical object-oriented programmers who are used
to seeing a class declaration with the method declarations nested within it. If you’ve used this
style before, you might want to give this next example a try. Again, don’t worry if there are parts
of the code you don’t understand:
/* Add a method to the Function object that can be used to declare methods. */
Function.prototype.method = function(name, fn) {
this.prototype[name] = fn;
};
/* Anim class, with methods created using a convenience method. */
var Anim = function() {
...
};
Anim.method('start', function() {
...
});
Anim.method('stop', function() {
...
});
Function.prototype.method allows you to add new methods to classes. It takes two arguments.
The first is a string to use as the name of the new method, and the second is a function
that will be added under that name.
You can take this a step further by modifying Function.prototype.method to allow it to be
chained. To do this, you simply return this after creating each method. We devote Chapter 6
to chaining:
/* This version allows the calls to be chained. */
Function.prototype.method = function(name, fn) {
this.prototype[name] = fn;
return this;
};
/* Anim class, with methods created using a convenience method and chaining. */
var Anim = function() {
...
};
Anim.
method('start', function() {
...
}).
method('stop', function() {
...
});
You have just seen five different ways to accomplish the same task, each using a slightly
different style. Depending on your background, you may find one more appealing than another.
This is fine; JavaScript allows you to work in the style that is most appropriate for the project at
hand. Each style has different characteristics with respect to code size, efficiency, and performance.
A Loosely Typed Language
In JavaScript, you do not declare a type when defining a variable. However, this does not mean
that variables are not typed. Depending on what data it contains, a variable can have one of
several types. There are three primitive types: booleans, numbers, and strings (JavaScript differs
from most other mainstream languages in that it treats integers and floats as the same type).
There are functions, which contain executable code. There are objects, which are composite
datatypes (an array is a specialized object, which contains an ordered collection of values).
Lastly, there are the null and undefined datatypes. Primitive datatypes are passed by value,
while all other datatypes are passed by reference. This can cause some unexpected side effects
if you aren’t aware of it.
As in other loosely typed languages, a variable can change its type, depending on what
value is assigned to it. The primitive datatypes can also be cast from one type to another. The
toString method converts a number or boolean to a string. The parseFloat and parseInt functions
convert strings to numbers. Double negation casts a string or a number to a boolean:
var bool = !!num;
Loosely typed variables provide a great deal of flexibility. Because JavaScript converts type
as needed, for the most part, you won’t have to worry about type errors.
Functions As First-Class Objects
In JavaScript, functions are first-class objects. They can be stored in variables, passed into other
functions as arguments, passed out of functions as return values, and constructed at run-time.
These features provide a great deal of flexibility and expressiveness when dealing with functions.
As you will see throughout the book, these features are the foundation around which you will
build a classically object-oriented framework.
You can create anonymous functions, which are functions created using the function()
{ ... } syntax. They are not given names, but they can be assigned to variables. Here is an
example of an anonymous function:
/* An anonymous function, executed immediately. */
(function() {
var foo = 10;
var bar = 2;
alert(foo * bar);
})();
This function is defined and executed without ever being assigned to a variable. The pair
of parentheses at the end of the declaration execute the function immediately. They are empty
here, but that doesn’t have to be the case:
/* An anonymous function with arguments. */
(function(foo, bar) {
alert(foo * bar);
})(10, 2);
This anonymous function is equivalent to the first one. Instead of using var to declare the
inner variables, you can pass them in as arguments. You can also return a value from this function.
This value can be assigned to a variable:
/* An anonymous function that returns a value. */
var baz = (function(foo, bar) {
return foo * bar;
})(10, 2);
// baz will equal 20.
The most interesting use of the anonymous function is to create a closure. A closure is
a protected variable space, created by using nested functions. JavaScript has function-level scope.
This means that a variable defined within a function is not accessible outside of it. JavaScript is
also lexically scoped, which means that functions run in the scope they are defined in, not the
scope they are executed in. These two facts can be combined to allow you to protect variables by
wrapping them in an anonymous function. You can use this to create private variables for classes:
/* An anonymous function used as a closure. */
var baz;
(function() {
var foo = 10;
var bar = 2;
baz = function() {
return foo * bar;
};
})();
baz(); // baz can access foo and bar, even though it is executed outside of the
// anonymous function.
The variables foo and bar are defined only within the anonymous function. Because the
function baz was defined within that closure, it will have access to those two variables, even
after the closure has finished executing. This is a complex topic, and one that we touch upon
throughout the book. We explain this technique in much greater detail in Chapter 3, when we
discuss encapsulation.
The Mutability of Objects
In JavaScript, everything is an object (except for the three primitive datatypes, and even they
are automatically wrapped with objects when needed). Furthermore, all objects are mutable.
These two facts mean you can use some techniques that wouldn’t be allowed in most other
languages, such as giving attributes to functions:
function displayError(message) {
displayError.numTimesExecuted++;
alert(message);
};
displayError.numTimesExecuted = 0;
It also means you can modify classes after they have been defined and objects after they
have been instantiated:
/* Class Person. */
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype = {
getName: function() {
return this.name;
},
getAge: function() {
return this.age;
}
}
/* Instantiate the class. */
var alice = new Person('Alice', 93);
var bill = new Person('Bill', 30);
/* Modify the class. */
Person.prototype.getGreeting = function() {
return 'Hi ' + this.getName() + '!';
};
/* Modify a specific instance. */
alice.displayGreeting = function() {
alert(this.getGreeting());
}
In this example, the getGreeting method is added to the class after the two instances are
created, but these two instances still get the method, due to the way the prototype object works.
alice also gets the displayGreeting method, but no other instance does.
Related to object mutability is the concept of introspection. You can examine any object at
run-time to see what attributes and methods it contains. You can also use this information to
instantiate classes and execute methods dynamically, without knowing their names at development
time (this is known as reflection). These are important techniques for dynamic scripting
and are features that static languages (such as C++) lack.
Most of the techniques that we use in this book to emulate traditional object-oriented
features rely on object mutability and reflection. It may be strange to see this if you are used to
languages like C++ or Java, where an object can’t be extended once it is instantiated and classes
can’t be modified after they are declared. In JavaScript, everything can be modified at run-time.
This is an enormously powerful tool and allows you to do things that are not possible in those
other languages. It does have a downside, though. It isn’t possible to define a class with a particular
set of methods and be sure that those methods are still intact later on. This is part of
the reason why type checking is done so rarely in JavaScript. We cover this in Chapter 2 when
we talk about duck typing and interface checking.
Inheritance
Inheritance is not as straightforward in JavaScript as in other object-oriented languages. JavaScript
uses object-based (prototypal) inheritance; this can be used to emulate class-based (classical)
inheritance. You can use either style in your code, and we cover both styles in this book. Often
one of the two will better suit the particular task at hand. Each style also has different performance
characteristics, which can be an important factor in deciding which to use.
CSS Shorthand - 1
Ok. Let’s set the record straight. There is no official guide for each and every CSS shorthand property value. So let’s work together and put one together shall we? Ok. Straight to the business. Anytime I’ve ran into a specification (besides the confusing mess at the W3C), it turns into showing off a couple of examples and you’re supposed to be set on your way. Well well. Over the years, I’ve found quite some interesting unknown quirky facts about these shorthands… hence this Guide was born.
Background
Backgrounds can be tricky. Nevertheless, effective when condensed correctly. The syntax for declaring the background shorthand values are as follows:
background properties
element {
background-color: color || #hex || (rgb / % || 0-255);
background-image:url(URI);
background-repeat: repeat || repeat-x || repeat-y || no-repeat;
background-position: X Y || (top||bottom||center) (left||right||center);
background-attachment: scroll || fixed;
}
Believe it or not, all these properties can be combined into one single background property as follows:
the background shorthand property
element {
background:
#fff
url(image.png)
no-repeat
20px 100px
fixed;
}The Unknown
Often times developers find themselves wondering What if I leave out this value or that one? How will that effect the design?
. Good questions.
By default, the background property will assume the following when you do not declare each value of the properties.
default background property values
element {
background-color: transparent;
background-image: none;
background-repeat: repeat;
background-position: top left;
background-attachment: scroll;
}Lesson learned: be careful on what you don’t declare. By chosing to not declare a value on a shorthand property, you are explicitly declaring the above default settings. For example, let’s look at the following example.
background shorthand example (unexplicit)
element {
background:red url(image.png);
}This would be the same as declaring the following values:
background shorthand example (explicit)
element {
background:red url(image.png) repeat top left scroll;
}Font
Font is perhaps the trickiest. However, it follows the same rules as the background shorthand property. All that you do not declare will have unexplicit values. Here is the font shorthand specification:
font properties
element {
font-style: normal || italic || oblique;
font-variant:normal || small-caps;
font-weight: normal || bold || bolder || || lighter || (100-900);
font-size: (number+unit) || (xx-small - xx-large);
line-height: normal || (number+unit);
font-family:name,"more names";
}The default values for the font shorthand property are as follows:
default font property values
element {
font-style: normal;
font-variant:normal;
font-weight: normal;
font-size: inherit;
line-height: normal;
font-family:inherit;
}And of course without any further ado. The font shorthand property syntax:
the font shorthand property
element {
font:
normal
normal
normal
inhert/
normal
inherit;
}Here is where it gets tricky. The fact that font-style, font-variant, and font-weight all come “normal” out of the box, you may need to pay a little more close attention when you’re styling elements that come with default browser styles like <h1> - <h6> or <strong> and <em>. For example, styling the strong element:
strong element styled with font
strong {
font:12px verdana;
}By writing the above into your style sheet, you will be unexplicitly removing the font-weight:bold default browser style that is applied to strong elements.
Last but not least (for -font- that is), a real world example:
font shorthand property example (unexplicit)
p {
font:bold 1em/1.2em georgia,"times new roman",serif;
}This would be the same as declaring the following properties:
the font shorthand property (explicit)
p {
font-style:normal;
font-variant:normal;
font-weight:bold;
font-size:1em;
line-height:1.2em;
font-family:georgia,"times new roman",serif;
}Border
Let’s not waste time discussing the warnings. The same rules apply from here on out. This is all you need to know
border properties
element {
border-width: number+unit;
border-style: (numerous);
border-color: color || #hex || (rgb / % || 0-255);
}becomes this:
the border shorthand propertie
element {
border:
4px
groove
linen
}Don’t ask me how that would look. The fact that “linen” is in there, things could get scary. Nevermind the matter, here is where ‘border’ gets funny.
border examples
p {
border:solid blue;
}
/* will create a '3px' solid blue border...
who knows where 3px came from?? */
p {
border:5px solid;
}
/* will create 5px solid 'black' border...
default must be black?? */
p {
border:dashed;
}
/* will create a '3px' dashed 'black' border...
3px black lines unite! */
p { border:10px red; }
p { border:10px; }
p { border:red; }
/* these just don't even work */
One thing to specially take note about declaring a border without a color, the default will be ‘black’ unless otherwise noted through an explicit or inherited ‘color’ property. See the following examples:
border color examples
p {
border:dotted;
color:red;
}
/* will create a 3px dotted red border */
/* ----------------------------- */
body {
color:blue;
}
body p {
border:5px solid;
}
/* will create a 5px solid blue border */
/* ----------------------------- */Get it? Got it. Good! (isn’t that a song?) Anyway. On with this
Margin and Padding
These are by far the easiest. Just think about the hands of a clock starting at noon, and follow the hour. For the sake of brevity, we’ll be working with margin (since it’s a shorter word). So for all cases of margin, the same rules apply to padding.
margin properties.
element {
margin-top: number+unit;
margin-right: number+unit;
margin-bottom: number+unit;
margin-left: number+unit;
}… combined into the margin superpowers:
the margin shorthand property
/* top right bottom left */
element {
margin: auto auto auto auto;
}Of course, you may declare your margin with one, two, three, or four values. Here is how each scenario will be played out:
margin fun
/* adds a 10px margin to all four sides */
element {
margin:10px;
}
/* adds a 20px margin to top and bottom
and a 5px margin to left and right */
element {
margin:20px 5px;
}
/* adds a 50px margin to top
and a 10px margin to left and right
and a 300px margin to bottom */
element {
margin:50px 10px 300px;
}
Understood? Let’s keep going. This is fun isn’t it! (whatever, you like it).
Outline
Quite frankly, this property has dropped off the existence of the design radar. Mainly because of lack of browsers supporting this CSS 2.1 standard (yep, it’s an actual property), but nonetheless, it too has a shorthand property. This property follows the exact same (or same exact - they mean the same thing) specification as the ‘border’ shorthand property. But, for purposes of this being a Guide, it must be here. So:
outline properties
element {
outline-width: number+unit;
outline-style: (numerous);
outline-color: color || #hex || (rgb / % || 0-255);
}Outline written as shorthand:
outline shorthand property
element {
outline:3px dotted gray;
}For purposes of trying to keep things from repeating, please see the border shorthand section on this document to understand the odds, ends, and quirks of the outline property.
List-style
This is it. The last one. It’s rarely used frequently. Hence rarely. That is why I kept it until the end (sorry, the best was first in my own opinion). Here is the list-style properties:
list-style properties
element {
list-style-type: (numerous);
list-style-position:inside || outside;
list-style-image:url(image.png);
}Here is the defaults:
list-style property defaults
element {
list-style-type:disc;
list-style-position:outside;
list-style-image:none;
}And for the sake of final brevity. Here is a simple example:
list-style shorthand property example
ul li {
list-style:square inside url(image.png);
}
/* in this particular case if image.png is not available
then a square will be provided as secondary */That’s it!
I hope this provides years and years of referencing for all your CSS shorthand needs. When CSS3 is finally outside its working draft, expect to see this guide updated as necessary.
CSS: Block Box, Line Box and Inline Box
The short definition is that block-level elements are elements that create blocks or large groupings of text.
block-level elements have some specific distinctions from inline elements:
* block-level elements generally can contain text, data, inline elements, or other block-level elements.
* block-level elements generally begin new lines of text.
* block-level elements inherit directionality information differently from inline elements.
Examples:
* <p></p>
* <blockquote></blockquote>
* <table></table>
Inline Elements
The short definition is that inline elements are elements that are found in the text of the HTML document. They are also sometimes called text level elements.
Inline elements have some specific distinctions from block-level elements:
* Inline elements generally only contain text, data or other inline elements. They are usually "smaller" than block-level elements.
* Inline elements do not generally begin new lines of text.
* Inline elements inherit directionality information differently from block-level elements.
Also Known As: text level elements
Examples:
* <span></span>
* <strong></strong>
* <abbr></abbr>
There are block-level boxes, line boxes and inline-level boxes. A block-level box is like a paragraph. A line box is like a line of text. And inline-level boxes are like words inside a line.
The precise rules are below and in other modules, but in summary, a block-level box contains either other block-level boxes (e.g., a section containing paragraphs, or a table containing rows), or it contains line boxes (e.g., a paragraph containing lines of text). A line box contains inline-level boxes (e.g., a line with words in different styles). An inline-level box may contain either text interspersed with more inline-level boxes, or it may contain a block-level box (e.g., a small table that is rendered inline).
For example, a fragment of HTML such as
<ul>
<li>The first item in the list.
<li>The second item.
</ul>
may result in one block-level box for the ul element, containing two block-level boxes for the two li elements, each of which has one line box (i.e., one line of text). Both line boxes contain two inline-level boxes: one that contains the list bullet and one that contains the text.
Note how the li is transformed into multiple boxes, including one that contains generated content, viz., the list bullet, which is not present in the source document.
If the document is rendered in a narrow window, it may be that the li elements get transformed into even more boxes, because the text requires multiple lines. And if the document is rendered on paper, it may be that a page break falls in the middle of the ul element, so that it is not transformed into a single block-level box, but into two smaller ones, each on a different page.