CSS quirk

CSS stands for ‘Cascading Style Sheets’ and once you grasp the concept, it makes a lot of sense. So if you define a style for your paragraph text, say


.normal-paragraph {
    font-family: Helvetica;
    color: #333;

and later want to have a paragraph in the body be a different font, you can define and apply a new style.

.different-font {
    font-family: Times;

and apply it to the paragraph.

I was trying to do this with padding and it wasn’t working. Specifically I was adding a style to the heading to remove padding.


<h3 class='linkSection pad-no-bottom'>

What I thought should happen was that the browser would get the padding information from the linkSection CSS and then adjust it based on the padding information in the pad-no-bottom class. However, what it does is read the style information in the order in which it appears in the CSS file—not the order in which you call the classes. So I pulled all of my padding classes out of the main CSS file and put them into a separate file that is called last. I did the same thing for all of the other override classes as well. e.g. .indent, .italic, .centered, etc.

Pure.css Miscellaneous Stuff

I’m exploring Pure.css for responsive design and I am running across things that I’ve never seen before. So I don’t have to look them up again, this post is a collection of them and some general observations about the css.

For some reason the GitHub repository for Pure.css doesn’t contain the actual base CSS. However, you can find it at the Yahoo CDN by removing the -min portion of the minified CSS link.
http://yui.yahooapis.com/pure/0.6.0/pure.css

The first 521 lines are from Normalize.css and some additions from the YUI team that basically clean up browser differences so that the Pure code will work the same on all browsers—even very old ones and obscure ones.

IE Hacks
If you browse through the code, you might notice lots of lines starting with asterisks. e.g.


    display: inline-block;
    *display: inline;

    width: 4.1667%;
    *width: 4.1357%;

Once again, StackOverflow provides an explanation.

It is a syntax error. So in CSS, it makes the property name invalid and stops it being parsed. Thanks to bugs in browsers, it is sometimes ignored.

[Therefore] the second declaration will be applied by IE7 and older (thus overriding the first declaration), while other browsers will ignore it and continue applying the first declaration instead.

While I was looking this up, I also found another IE hack.

\9 is a “CSS hack” specific to Internet Explorer 7, 8, & 9.

This simply means that the one specific line of CSS ending with a \9; in place of the ; is only valid in IE 7, 8, & 9.

width: 500px\9; means that a width of 500 pixels (same result as width: 500px;) will only be applied while using IE 7, 8, & 9.

All other browsers will ignore width: 500px\9; entirely, and therefore not apply width: 500px; to the element at all.

It turns out that \0 can be used for IE 10.

:not

Pseudo-class :not
The :not pseudo-class represents an element that is not represented by its argument.

There aren’t many occasions where this is used in the file. The major one is to give padding, display, and border parameters when the a form is not one of the 14 form types listed in the previous block of css. e.g. .pure-form input:not([type]) {

Attribute Wildcard Selector


.pure-g [class *= "pure-u"] {
    font-family: sans-serif;
}

The *= is an attribute wildcard selector. In the example above, it looks for any child element under .pure-g that has a class that contains pure-u. Since Pure Grids consist of two types of classes: the grid class (pure-g) and within the grid class the unit classes (pure-u or pure-u-*) it basically resets all of the unit classes to use sans-serf as the default.

From the documentation, suppose you want to change the font to a serif font. Use this code:


html, button, input, select, texture, .pure-g [class *= "pure-u"] {
    font-family: Georgia, Times, "Times New Roman", serif;
}

Media Queries
The responsive part of responsive design relies on media queries. In the past, there were only two that you had to worry about—print and screen. With the advent of smartphones and tablets, you need to be able to adapt the content to the screen size in ways that were not necessary before. Media queries can be used to check the width and height of the viewport, the width and height of the device, the device orientation, and the device resolution, and other properties that you might need for your design. A huge list can be found at W3Schools. Pure.css only uses the screen media type along with the screen width expressed in ems to provide styling for five sizes. You refer to the sizes using suffixes on the pure unit styles. No suffix is for screens less than 35.5 ems (568 pixels), -sm is for the next size up, followed by -md. -lg and -xl are for the largest screens.

As with the css for the grid, you can find it at the Yahoo CDN by removing the -min portion of the minified CSS link.
http://yui.yahooapis.com/pure/0.6.0/grids-responsive.css

As they explain on their site. Using ems for media queries is much better for people who set their browser default to a larger size and for users who zoom in to the content.

Font size
Pure uses the default font size for the browser for all of the elements. Combined with the media query above, this means that the font size will scale with the viewport and zoom level so you don’t need to worry about it. If you do want to make the sizes vary from the default, e.g. possibly with captions or super-emphasis, then use percentages to increase the size.

One interesting font definition that I had not seen before is assigning the font size and line height at the some time. This code makes italic 85% of the normal size for the element but keeps the line height at 1 em so that it doesn’t interrupt the flow.


font: italic 85%/1 arial, sans-serif;

Browser Cookies with PHP and JavaScript

I have a game that I am in the process of updating. Originally it passed scores in with the URL, but I decided to update it so that the scores are not visible. My first thought was to use session variables, but since I want to change the scores in response to calculations that are done in JavaScript, that isn’t feasible. A better way is to use cookies. When I first enter a page, I set or get the cookies with PHP. I want the game levels to persist from visit to visit but the scores are only kept for the session.


// Initialize the cookies with PHP. Keep the group and level around but make the scoring session cookies
// If the cookie is set by the code, it is not available until the next page load
$cookie_name = "VPA_group";
$cookie_value = "MW1";
if( !isset($_COOKIE[$cookie_name]) ) {
    setcookie($cookie_name,$cookie_value,$cookie_time,$cookie_path,$cookie_domain,$cookie_secure,$cookie_httponly);
}
$group  = isset($_COOKIE["VPA_group"])  ? $_COOKIE["VPA_group"]   : $cookie_value;

$cookie_name = "VPA_WFF";
$cookie_value = "Wide";
if( !isset($_COOKIE[$cookie_name]) ) {
    setcookie($cookie_name,$cookie_value,$cookie_time,$cookie_path,$cookie_domain,$cookie_secure,$cookie_httponly);
}
$WFF    = isset($_COOKIE["VPA_WFF"])    ? $_COOKIE["VPA_WFF"]     : $cookie_value;

$cookie_name = "VPA_cor";
$cookie_value = 0;
if( !isset($_COOKIE[$cookie_name]) ) {
    setcookie($cookie_name,$cookie_value);
}
$cor    = isset($_COOKIE["VPA_cor"])    ? $_COOKIE["VPA_cor"]     : $cookie_value;

$cookie_name = "VPA_inc";
$cookie_value = 0;
if( !isset($_COOKIE[$cookie_name]) ) {
    setcookie($cookie_name,$cookie_value);
}
$inc    = isset($_COOKIE["VPA_inc"])    ? $_COOKIE["VPA_inc"]     : $cookie_value;

$cookie_name = "VPA_screen";
$cookie_value = 0;
if( !isset($_COOKIE[$cookie_name]) ) {
 setcookie($cookie_name,$cookie_value);
}
$screen = isset($_COOKIE["VPA_screen"]) ? $_COOKIE["VPA_screen"]  : $cookie_value;

Once I have the values, I need to let JavaScript know what they are.


<script>
    <?php
        echo "var cor = $cor;\n";
        echo "var inc = $inc;\n";
        echo "var screen = $screen;\n";

        echo "var group = \"$group\";\n";
        echo "var WFF = \"$WFF\";\n";
        echo "var cookie_days = \"$cookie_days\";\n";
    ?>
</script>

Then I can use JavaScript to change them, as I described in the previous post.


function goNext() {
    setCookie('VPA_cor',cor,'N');
    setCookie('VPA_inc',inc,'N');
    setCookie('VPA_screen',screen,'N');
    window.location="ThisGame.php";
}

function changeLevel(cookieName, cookieValue) {
    cor = 0;
    inc = 0;
    screen = 0;
    setCookie('VPA_cor',cor,'N');
    setCookie('VPA_inc',inc,'N');
    setCookie('VPA_screen',screen,'N');
    setCookie(cookieName, cookieValue, 'Y');
}

function setCookie(cname, cvalue, set_time) {
    var expires = '';
    if ( set_time == 'Y' ) {
        var d = new Date();
        d.setTime(d.getTime() + (cookie_days*24*60*60*1000));
        expires = "expires="+d.toUTCString();
    }
    //alert('cname ' + cname + 'group ' + cvalue + 'time ' + expires);
    document.cookie = cname + "=" + cvalue + "; " + expires;
}
</script>

Browser Cookies with JavaScript

Using JavaScript to set and get cookies is pretty straightforward. I wrote a simple function to set cookies for a game I’m working on. This code initializes/resets the cookies.


var cookie_days = 30;
var cor = 0;
var inc = 0;
var screen = 0;
var level = "MW1";
setCookie('VPA_cor',cor,'N');
setCookie('VPA_inc',inc,'N');
setCookie('VPA_screen',screen,'N');
setCookie('VPA_level',level,'Y');

function setCookie(cname, cvalue, set_time) {
var expires = '';
if ( set_time == 'Y' ) {
    var d = new Date();
    d.setTime(d.getTime() + (cookie_days*24*60*60*1000));
    expires = "expires="+d.toUTCString();
}
//alert('cname ' + cname + 'group ' + cvalue + 'time ' + expires);
document.cookie = cname + "=" + cvalue + "; " + expires;
}

Note that the JavaScript code for setting and resetting a cookie is the same. One caveat is that if the cookie has been set outside of JavaScript, e.g. in PHP, then it is possible that the httponly has been set to TRUE. In that case you cannot modify an existing cookie with JavaScript.

You can get the value of the cookies with this code.


var cookie_name = 'VPA_cor';
var cor = retrieve_cookie(cookie_name);

In my code, I set the cookies with PHP, so the path is already set. If you initialize a cookie with JavaScript, you can set the path by adding a path parameter.


 document.cookie = name + '=' + value + ';' +
                   'expires=' + expires + ';' +
                   'path=' + path + ';';

Browser Cookies with PHP

PHP
Like other headers, cookies must be sent before any output from your script (this is a protocol restriction). This requires that you place calls to this function prior to any output, including and tags as well as any whitespace. PHP.net

Here is an example of a cookie that checks to see how many times a person has visited the site. Note that it expires in 30 days.


$cookie_name = "VPA";
$cookie_days = 30;
$cookie_time = time()+60*60*24*$cookie_days;
$cookie_path = '';
$cookie_domain = '';
$cookie_secure = false;
$cookie_httponly = true;

if( !isset($_COOKIE[$cookie_name]) ) {
    $cookie_value = 0;
} else {
  $cookie_value = $_COOKIE[$cookie_name] + 1;
}
setcookie($cookie_name,$cookie_value,$cookie_time,$cookie_path,$cookie_domain,$cookie_secure,$cookie_httponly);

In your code you can check for the value of the cookie like this:


echo "Cookie VPA is $_COOKIE[VPA]";

The value can be a number or text. Once a cookie is created, you can update the value in the body of your code.


setcookie("VPA","red",$cookie_time);
echo $_COOKIE["VPA"];

Not that I switched from a number to alpha in this example. The cookies don’t care what the value is or if the type changes. Note that you cannot get the cookie expiration time. And if you leave it off in your setcookie, it will be reset to Session.

To get rid of a cookie, set its value to null and time to something in the past—zero works.


setcookie($cookie_name,'',0);
e.g.
set cookie('VPA','',0);