Best css questions in May 2012

What's the difference in the :not() selector between jQuery and CSS?

19 votes

I have this layout:

<div id="sectors">
    <h1>Sectors</h1>
    <div id="s7-1103" class="alpha"></div>
    <div id="s8-1104" class="alpha"></div>
    <div id="s1-7605" class="beta"></div>
    <div id="s0-7479"></div>
    <div id="s2-6528" class="gamma"></div>
    <div id="s0-4444"></div>
</div>

With these style rules:

#sectors {
    width: 584px;
    background-color: #ffd;
    margin: 1.5em;
    border: 4px dashed #000;
    padding: 16px;
    overflow: auto;
}

#sectors h1 {
    font-size: 2em;
    font-weight: bold;
    text-align: center;
}

#sectors div {
    float: left;
    position: relative;
    width: 180px;
    height: 240px;
    margin: 16px 0 0 16px;
    border-style: solid;
    border-width: 2px;
}

#sectors div:nth-of-type(3n+1) {
    margin-left: 0;
}

#sectors div::after {
    display: block;
    position: absolute;
    width: 100%;
    bottom: 0;
    font-weight: bold;
    text-align: center;
    text-transform: capitalize;
    background-color: rgba(255, 255, 255, 0.8);
    border-top-style: solid;
    border-top-width: 2px;
    content: attr(id) ' - ' attr(class);
}

#sectors div.alpha { color: #b00; background-color: #ffe0d9; }
#sectors div.beta  { color: #05b; background-color: #c0edff; }
#sectors div.gamma { color: #362; background-color: #d4f6c3; }

#sectors div.unassigned {
    color: #808080;
    background-color: #e9e9e9;
    opacity: 0.5;
}

#sectors div.unassigned::after {
    content: attr(id) ' - Unassigned';
}

#sectors div.unassigned:hover {
    opacity: 1.0;
}

I use jQuery to add the unassigned class to sectors that don't otherwise have one of the classes alpha, beta or gamma:

$('#sectors div:not(.alpha, .beta, .gamma)').addClass('unassigned');

And everything works flawlessly in modern browsers.

Interactive jsFiddle preview

But seeing as the :not() selector in jQuery is based on :not() in CSS3, I thought I could place it directly in my stylesheet so I wouldn't have to rely on an extra class added using jQuery. Besides, I'm not really interested in supporting older versions of IE, and other browsers have excellent support for the :not() selector.

So I try doing this (knowing I will only have sectors Α, Β and Γ in my layout):

#sectors div:not(.alpha, .beta, .gamma) {
    color: #808080;
    background-color: #e9e9e9;
    opacity: 0.5;
}

#sectors div:not(.alpha, .beta, .gamma)::after {
    content: attr(id) ' - Unassigned';
}

#sectors div:not(.alpha, .beta, .gamma):hover {
    opacity: 1.0;
}

But then it suddenly stops working — in all browsers! My unassigned sectors aren't grayed out, faded out or labeled 'Unassigned' anymore.

Updated but not so interactive jsFiddle preview

Why is the selector failing here? Shouldn't :not() work identically in both jQuery and CSS since jQuery borrows from the CSS3 standard, or is there something I'm missing? Is there even a workaround for this if I really want to avoid relying on a script?

Why is the selector failing here? Shouldn't :not() work identically in both jQuery and CSS since jQuery borrows from the CSS3 standard, or is there something I'm missing?

Perhaps it should, but it turns out that it doesn't. jQuery extends the :not() selector such that you can pass any selector to it, no matter how complex it may be, and I suspect that this is for parity with the .not() method, which also accepts any arbitrarily complex selector and filters accordingly. It does in a way maintain a CSS-like syntax, but it extends from what's defined in the standard.

As another example, this works just fine (I know it's an incredibly ludicrous example compared to what's given in the question, but it's just for illustrative purposes):

/* 
 * Select any section
 * that's neither a child of body with a class
 * nor a child of body having a descendant with a class.
 */
$('section:not(body > [class], body > :has([class]))')

jsFiddle preview

Remember that passing a comma-separated list of selectors to :not() means filtering elements that don't match any of the listed selectors.

Now the :not() pseudo-class in CSS3, on the other hand, is very limited by itself. You can only pass a single simple selector as an argument to :not(). This means you can pass only any one of these at a time:

  • Universal selector (*), optionally with a namespace

  • Type selector (a, div, span, ul, li, etc), optionally with a namespace

  • Attribute selector ([att], [att=val], etc), optionally with a namespace

  • Class selector (.class)

  • ID selector (.id)

  • Pseudo-class (:pseudo-class)

So, here are the differences between jQuery's :not() selector and CSS3's :not() selector:

  1. First and foremost, to answer the question directly: you can't pass a comma-separated selector list.1 For example, while the given selector works in jQuery as demonstrated in the fiddle, it isn't valid CSS3:

    /* If it's not in the Α, Β or Γ sectors, it's unassigned */
    #sectors div:not(.alpha, .beta, .gamma)
    

    Is there even a workaround for this if I really want to avoid relying on a script?

    Thankfully, in this case, there is. You simply have to chain multiple :not() selectors, one after another, in order to make it valid CSS3:

    #sectors div:not(.alpha):not(.beta):not(.gamma)
    

    It doesn't make the selector that much longer, but the inconsistency and inconvenience remain evident.

    Updated interactive jsFiddle preview

  2. You can't combine simple selectors into compound selectors for use with :not(). This works in jQuery, but is invalid CSS3:

    /* Do not find divs that have all three classes together */
    div:not(.foo.bar.baz)
    

    You'll need to split it up into multiple negations (not just chain them!) to make it valid CSS3:

    div:not(.foo), div:not(.bar), div:not(.baz)
    

    As you can see, this is even more inconvenient than point 1.

  3. You can't use combinators. This works in jQuery, but not CSS:

    /* 
     * Grab everything that is neither #foo itself nor within #foo.
     * Notice the descendant combinator (the space) between #foo and *.
     */
    :not(#foo, #foo *)
    

    This one is particularly nasty, primarily because it has no proper workaround. There are some loose workarounds (1 and 2), but they usually depend on the HTML structure and are therefore very limited in utility.

It's worth noting that the CSS4 Selectors spec enhances the :not() selector to allow a comma-separated list of compound selectors. Compound selectors are, quite simply, simple selectors combined (compounded) together, without combinators separating them. This means that the jQuery selectors shown in points 1 and 2 above will probably become equivalent and valid CSS4 as well, which will make the pseudo-class much, much more useful when CSS parsers start to support it in the coming years.

Unfortunately, it still does not allow combinators as shown in point 3, at least not as of this writing, so jQuery still has kind of the upper hand here. That shouldn't be much of a problem though, IMO, as you should rarely ever need to use combinators within the :not() selector (but that's just my take on it).2


1 Although this article says that you can pass a comma-separated list of selectors to :not() in Firefox 3, you're not supposed to be able to. It worked because of a bug in Firefox 3 for which I can't find the ticket anymore, but it shouldn't work until future browsers implement future standards. Seeing how often that article is cited to date, I've left a comment to this effect, but seeing also how old the article is and how infrequently the site is being updated, I'm really not counting on the author coming back to fix it.

2 On the other hand, I have no personal objections to using the .not() method with complex selectors and combinators myself. As a matter of fact, the documentation for jQuery's :not() selector states: "The .not() method will end up providing you with more readable selections than pushing complex selectors or variables into a :not() selector filter. In most cases, it is a better choice."

jqGrid does not render correctly in Chrome/Chrome Frame

18 votes

Currently using Chrome v19.0.1084.46 (Official Build 135956) beta-m jqGrid 4.3.2 (latest release)

The problem is that no matter the size of my grid, columns, or containing div, a small fraction of my last column gets pushed beyond the edge of the grid, causing horizontal scroll bars to appear, which should not happen. See below:

grid

I've been fiddling with the following attributes on jqGrid to try and fix this:

  • width
  • autowidth
  • height
  • shrinkToFit
  • scrollOffset - Had the best luck with this one, but nothing repeatable.

I've also stripped down to the basic grid css only, thinking it might have been a rule I put in place...with no luck.

Has anyone else experienced this and/or found a solution to this? Help is much appreciated.

I updated today my Chrome to version 19, have reproduced the problem and made the corresponding quick&dirty fix:

I suggest to change the line of jqGrid code

isSafari = $.browser.webkit || $.browser.safari ? true : false;

to the following

isSafari = ($.browser.webkit || $.browser.safari) &&
    parseFloat($.browser.version)<536.5 ? true : false; // Chrome < version 19

The demo use the fix. The fixed version of jquery.jqGrid.src.js which I used in the demo you can get here.

I tested it in IE9 (v9.0.8112.16421), IE8 (8.0.6001.18702CO), Chrome 18.0.125.168, Chrome 19.0.1084.46, Safari 5.1.7 (7534.57.2), Firefox 12, Opera 11.62. In all the web browsers the demo has no horizontal scrollbars and it looks as following:

enter image description here

In the future it would be better to change the calculation of width of the grid more deep to have no direct dependency from any version number or web browser. I hope it will be possible if one would use more jQuery methods $.width and $.outerWidth in some places of jqGrid. In any way I hope that the above described fix would be already helpful for many jqGrid users.

UPDATED: I posted my suggestion to trirand as the bug report.

UPDATED 2: To be exactly there are three places in the code where are used the same $.browser.webkit || $.browser.safari construct as described above: inside setGridWidth, inside of getOffset, inside of calculation of the width of multiselect column, inside showHideCol and inside setGridWidth. The first three places uses isSafari variable. The last two places uses $.browser.webkit || $.browser.safari directly. One should replace in all the places the code

$.browser.webkit||$.browser.safari

to

($.browser.webkit || $.browser.safari) && parseFloat($.browser.version)<536.5

So one should do this in three places:

  1. at the definition of the isSafari (see me original post)
  2. inside of showHideCol
  3. inside of setGridWidth

You can download the fixed version of the jquery.jqGrid.src with all the fixes here. You can make the same changes in the code of jquery.jqGrid.src yourself if you have to use old version of jqGrid. To created minimized version for the production you can use any minimizer which you good know. I use for example Microsoft Ajax Minifier 4.0. Just install it and execute

AjaxMin.exe jquery.jqGrid.src-fixed3.js -o jquery.jqGrid.min-fixed3.js

As the result you will get jquery.jqGrid.min-fixed3.js which will be even smaller as original jquery.jqGrid.min.js. Even if you add the comment header to the file (see modified file) the file will be still smaller as original version of jquery.jqGrid.min.js.

After some iterations of my bug report and the improvements there are one more version of the fix where the method cellWidth was introduced:

cellWidth : function () {
    var $testDiv = $("<div class='ui-jqgrid' style='left:10000px'><table class='ui-jqgrid-btable' style='width:5px;'><tr class='jqgrow'><td style='width:5px;'></td></tr></table></div>"),
        testCell = $testDiv.appendTo("body")
            .find("td")
            .width();
        $testDiv.remove();
        return testCell !== 5;
}

See here. If you prefer to follow the way you can do this also. In the case in all places where isSafari or $.browser.webkit || $.browser.safari (in showHideCol and setGridWidth) are used you can use $.jgrid.cellWidth() instead.

UPDATED 3: Today was published jqGrid 4.3.3 which contains the fix which I described above (the cellWidth method). So I recommend all to use the new version.

What JavaScript should be included in the <head> and what included in the <body>?

17 votes

I am confused about which JavaScript should be included where?

For instance:

  • Where should one include the jQuery libraries? In the <head> or before the closing </body> element?

  • If the JavaScript is defined at the bottom in the <body>, can it be used inline in the body?

  • If it blocks parallel downloads, then why is it never said to include your CSS at the bottom?

The Place of the <script> Element

The script elements block progressive page downloads.
Browsers download several components at a time, but when they encounter an external script, they stop further downloads until the script file is downloaded, parsed, and executed.
This hurts the overall page time, especially if it happens several times during a page load.
To minimize the blocking effect, you can place the script element toward the end of the page, right before the closing tag.
This way there will be no other resources for the script to block. The rest of the page components will be downloaded and already engaging the user.
The worst antipattern is to use separate files in the head of the document:

<!doctype html>
<html>
<head>
    <title>My App</title>
    <!-- ANTIPATTERN -->
    <script src="jquery.js"></script>
    <script src="jquery.quickselect.js"></script>
    <script src="jquery.lightbox.js"></script>
    <script src="myapp.js"></script>
</head>
<body>
...
</body>
</html>

A better option is to combine all the files:

<!doctype html>
<html>
<head>
    <title>My App</title>
    <script src="all_20100426.js"></script>
</head>
<body>
    ...
</body>
</html>

And the best option is to put the combined script at the very end of the page:

<!doctype html>
<html>
<head>
    <title>My App</title>
</head>
<body>
    ...
    <script src="all_20100426.js"></script>
</body>

“JavaScript Patterns, by Stoyan Stefanov (O’Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750.”

CSS 3 Shape: "Inverse Circle"

15 votes

I want to create a shape, which i would describe as "inverse circle":

CSS Shape

The image is somehow inaccurate, because the black line should continue along the outer border of the div element.

Here is a demo of what i have at the moment: http://jsfiddle.net/n9fTF/

Is that even possible with CSS without images?

Update: CSS3 Radial Background Gradient Option

(For those browsers supporting it--tested in FF and Chrome--IE10, Safari should work too).

One "problem" with my original answer is those situations where one does not have a solid background that they are working against. This update creates the same effect allowing for a transparent "gap" between the circle and it's inverse cutout.

See example fiddle.

CSS

.inversePair {
    border: 1px solid black;
    display: inline-block;    
    position: relative;    
    height: 100px;
    text-align: center;
    line-height: 100px;
    vertical-align: middle;
}

#a {
    width: 100px;
    border-radius: 50px;
    background: grey;
    z-index: 1;
}

#b {
    width: 200px;
    /* need to play with margin/padding adjustment
       based on your desired "gap" */
    padding-left: 30px;
    margin-left: -30px;
    /* real borders */
    border-left: none;
    -webkit-border-top-right-radius: 20px;
    -webkit-border-bottom-right-radius: 20px;
    -moz-border-radius-topright: 20px;
    -moz-border-radius-bottomright: 20px;
    border-top-right-radius: 20px;
    border-bottom-right-radius: 20px;
    /* the inverse circle "cut" */
    background-image: -moz-radial-gradient(
        -23px 50%, /* the -23px left position varies by your "gap" */
        circle closest-corner, /* keep radius to half height */
        transparent 0, /* transparent at center */
        transparent 55px, /*transparent at edge of gap */
        black 56px, /* start circle "border" */
        grey 57px /* end circle border and begin color of rest of background */
    );
    background-image: -webkit-radial-gradient(-23px 50%, circle closest-corner, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 0) 55px, black 56px, grey 57px);
    background-image: -ms-radial-gradient(-23px 50%, circle closest-corner, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 0) 55px, black 56px, grey 57px);
    background-image: -o-radial-gradient(-23px 50%, circle closest-corner, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 0) 55px, black 56px, grey 57px);
    background-image: radial-gradient(-23px 50%, circle closest-corner, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 0) 55px, black 56px, grey 57px);
}

Original Answer

Took more effort than I expected to get the z-indexing to work (this seems to ignore the negative z-index), however, this gives a nice clean look (tested in IE9, FF, Chrome):

HTML

<div id="a" class="inversePair">A</div>
<div id="b" class="inversePair">B</div>

CSS

.inversePair {
    border: 1px solid black;
    background: grey;
    display: inline-block;    
    position: relative;    
    height: 100px;
    text-align: center;
    line-height: 100px;
    vertical-align: middle;
}

#a {
    width: 100px;
    border-radius: 50px;
}

#a:before {
    content:' ';
    left: -6px;
    top: -6px;
    position: absolute;
    z-index: -1;
    width: 112px; /* 5px gap */
    height: 112px;
    border-radius: 56px;
    background-color: white;
} 

#b {
    width: 200px;
    z-index: -2;
    padding-left: 50px;
    margin-left: -55px;
    overflow: hidden;
    -webkit-border-top-right-radius: 20px;
    -webkit-border-bottom-right-radius: 20px;
    -moz-border-radius-topright: 20px;
    -moz-border-radius-bottomright: 20px;
    border-top-right-radius: 20px;
    border-bottom-right-radius: 20px;
}

#b:before {
    content:' ';
    left: -58px;
    top: -7px;
    position: absolute;
    width: 114px; /* 5px gap, 1px border */
    height: 114px;
    border-radius: 57px;
    background-color: black;
} 

Animating a changing ranking table

14 votes

I have a ranking table which changes every second. I want to animate the table rows smoothly (not necessarily every second; maybe every 5 seconds).

A quick search revealed this jQuery plugin, based on this animated table sort. For my purposes, it looks a bit too much like a sports ranking, and the code is outdated and unmaintained.

Are there alternative plugins/libraries to animate changing ranking tables?

There is an interesting post on stackoverflow on your same subject: Using jquery, how to I animate adding a new list item to a list?

Of course it should be changed a little bit, because maybe you want to add more than one item to the list.

But what you can do is to refresh it every X seconds, and for each of the list item add the item in an animated way.

Is there a way to select the first character? :first-letter does not seem to work

12 votes

Example problem: http://jsfiddle.net/6WYXk/

I have some html: <p>% hello world</p>

I want to make the % bold. To do this usually I would write this in CSS:

p:first-letter
{
    font-weight: bold;
}​

However that makes the % and the h bold.

Ideally I'd like a psudeo selector of :first-character

Indeed, that's odd. Doen't work for other symbol chars as well and the same problem has been discussed elsewhere on SO as well.

You should try something like this:

<p>hello world</p>
p:before { content:"%"; font-weight: bold; padding-right: 5px;}

Try it yourself…

Creating a circular menu with CSS

12 votes

I'm trying to create a circular menu in CSS for a school project.

This is what the menu would look like:

enter image description here

I am not looking for the complete source just an idea how you experienced developers would do it.

I was thinking to create 8 triangles and then the middle to place a circlular div with position absolute; but the triangles, since they're created with borders, when you hover them they are not absolutely selectable. It's kinda buggy.

Is it even possible to create this with no images?

EDIT:

The menu will after by animated using jQuery; thus I will be using jQuery and jQuery UI but no other library and no images (i dont need the icons anyway). As for compatibility, should work on IE9+ / Chrome / Opera 11.52+ / Firefox 4+.

The following is a way to do it with HTML canvas, and it detects where the mouse is perfectly. It doesn't look the exact same as yours though, and I didn't add the icons or dividing lines (although anti-aliasing allows the background to show through a little between regions creating the illusion of lines being drawn).

http://jsfiddle.net/jcubed111/xSajL/

Edit - Bug Fix: http://jsfiddle.net/jcubed111/xSajL/2/

With more work you could make the canvas version look the same as your mock-up, my version is only to get the functionality down.

You could also make it look right with css, then overlay a clear a to detect mouse position and provide linking functionality. Of course, then you couldn't use :hover to change the look of the regions.

I've tested in Chrome 19 only.

Here's the full code below in case the link goes down:

HTML:

<a id='link'><canvas id='c' width='224' height='224' onmousemove="update(event);"></canvas></a>
<input id='i' />​​​​​​​​

CSS:

#c{
    width:224px;
    height:224px;
}​

JS (run on page load and uses jquery):

ctx = $('#c')[0].getContext('2d');


function update(E) {
    ctx.clearRect(0, 0, 224, 224);
    if (E === false) {
        mx = 112;
        my = 112;
    } else {
        mx = E.clientX;
        my = E.clientY;
    }

    mangle = (-Math.atan2(mx-112, my-112)+Math.PI*2.5)%(Math.PI*2);
    mradius = Math.sqrt(Math.pow(mx - 112, 2) + Math.pow(my - 112, 2));

    $('#i').val("Not over any region");
    $('#link').attr('href', '');
    for (i = 0; i < 8; i++) {
        angle = -Math.PI / 8 + i * (Math.PI / 4);

        if (((mangle > angle && mangle < (angle + Math.PI / 4)) || (mangle > Math.PI*15/8 && i==0)) && mradius<=112 && mradius>=69) {
            ctx.fillStyle="#5a5a5a";
            $('#i').val("In region "+i);
            $('#link').attr('href', '#'+i);
        } else {
            ctx.fillStyle="#4c4c4c";
        }

        ctx.beginPath();
        ctx.moveTo(112, 112);
        //ctx.lineTo(112+Math.cos(angle)*112, 112+Math.sin(angle)*112);
        ctx.arc(112, 112, 112, angle, angle + Math.PI / 4, false);
        ctx.lineTo(112, 112);
        ctx.fill();


    }

    ctx.fillStyle = "#f2f2f2";
    ctx.beginPath();
    ctx.arc(112, 112, 69, 0, 2 * Math.PI, false);
    ctx.fill();
}

update(false);​

Fonts become bold when changing orientation

11 votes

I use this in the html:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;">

and this in the CSS:

html { font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }\

also tried this:

html { -webkit-text-size-adjust: none; }

and yet for some reason this happens:

enter image description here enter image description here

Update: I tried removing all styling to see if any of my CSS is causing this, and the result was weird: when I'm not using any font rules, the font simply gets larger (it is not zoomed in since the zooming is locked by the HTML viewport attribute) also, only the small font gets larger, the headers remain the same. weird @#$%

Update 2: I played with the html/css and came to this conclusion - the only time when the text enlargement DOESN'T happen is when the text is contained inside the only element in the page - for example if all my body contains is p/span/div with text, it will not get enlarged. If I add another element with text in it, all text on page becomes enlarged in landscape mode.
I tried doing some research and looked through many mobile sites, and the result is the same - they all have this effect.

More Information than Real Solution

Based on my understanding of how things work according to this page and this page, all text will get refactored in landscape mode based on either -webkit-text-size-adjust: auto (the default for iOS) or by your setting of -webkit-text-size-adjust: 100%.

I do not believe the 100% setting is doing what you may think it is doing (an attempt to keep the text size the same). Rather, it is only affecting "how the text-inflating algorithm is applied" (per this page). I have not been able to track down exactly what that might mean; that is, what does 100% mean with respect to the inflation algorithm. My guess is, based upon this page's quote...

The first time a webpage is rendered, Safari on iOS gets the width of the block and determines an appropriate text scale so that the text is legible.

...that since the procedure happens only "the first time a webpage is rendered" that once the device is turned from portrait to landscape the inflation algorithm will "grow" the text based off the width change of the screen being wider, even when set at 100%.

Perhaps this is because 100% is in relation to the width difference of portrait to landscape. For example, this iPhone spec is 960 x 640. It may be that 100% means the inflation uses some direct relation of 960 x 640 (say, 960/640 x 100%), working out to be 1.5, which is then causing the "boldness" of the landscape text. If such is the case, then theoretically the -webkit-text-size-adjust would perhaps need to be set to 66.67% to keep it unaffected (returning the 1.5 factor to a 1). But I'm not convinced that it is so straight forward.

Ultimately, I think Andrey Bukati's answer of -webkit-text-size-adjust: none; is the only guarantee that no change in text sizing will occur. But it can have other, perhaps undesirable, affects.

Why does a filter gradient on a pseudo element not work in IE8?

9 votes

I want to create buttons like these: pseudo 3d button

In modern browsers the effect is created using inset box-shadow and filters.
For IE8 - pseudo-elements are chosen.
For IE7 - I use special tags wrapped in conditional comments.

Demo: http://jsfiddle.net/8M5Tt/68/embedded/result/

Main Question: Why don't filters work on pseudo elements in IE8?


Update:

I guess that filters do not work on css-generated content, despite the fact that it is not mentioned on this msdn page.

I solved my problem in IE8 by applying filters to conditional elements like I do for IE7.

Final demo: http://jsfiddle.net/matmuchrapna/8M5Tt/73/


Update 2:

I solved my problem, but the main question is still unanswered:

“Why don't filters work on pseudo elements in IE8?”

Started a bounty.

Update 3: I created testcase only for filters(and also -ms-filter) on ie8:

enter image description here

But the filters still don't want to work on pseudo-elements.

Update 4: I think Scotts answer is closest to truth.

The question is "Why don't filters work on pseudo elements in IE8?" The following is as close to a definitive answer as I can muster. It comes from the information on this page.

The gradient filter is a "procedural surface" (along with alphaimageloader). A procedural surface is defined so:

Procedural surfaces are colored surfaces that display between the content of an object and the object's background.

Read that carefully. It is essentially another "layer" you might say between the content of an object and that object's background. Do you see the answer to the question? What is created by :before and :after... Yes! Content. Specifically as MSDN notes:

The ::before and ::after pseudo-elements specify the location of content before and after an element in the document tree. The content attribute, in conjunction with these pseudo-elements, specifies what is inserted.

The generated content interacts with other boxes as if they were real elements inserted just inside their associated element.

Now, if it is content that is generated, then it is not an "object" containing content, but the content itself (which happens to have some behavior similar to an element object that might contain content).

Thus, there is no "object" containing "content" (since it is content) between which the filter can place a procedural surface for content generated by a pseudo-element (i.e. "false element"). A gradient must be applied to the object, and then the procedural surface is placed between it and the content.

How can I create this complicated layout using only CSS?

9 votes

OVERVIEW

I've read a bunch of the "vertical-centering with CSS" tutorials out there:

... but there is another component to my layout that is not represented in any of these methods in addition to the vertical centering.

layout.

There are 2 components to this layout. First, vertically & horizontally centering the content between the header and footer (which is a sticky footer). I have the code in a fiddle to demonstrate but I haven't been able to get this to work in IE (the code is at the bottom of the post).

The second component is where the green arrow is pointing. That represents a hidden element which is meant to expand vertically downwards when clicking on some of the text. However, I DO NOT WANT this expansion to move the content upward as if everything was being centered... I want this element to expand downwards without affecting the position of the content AND pushing the sticky footer down as it expands. In most cases, a browser scrollbar will appear.

So the effect of the hidden element expanding should be like a banner falling off an edge.

This is what the layout should look like after the hidden element has been expanded:

layout2


QUESTION

So how would I achieve this layout using only CSS and have it be cross-browser compatible Please let me know if I need to explain further to clarify confusion.


CODE SO FAR

Note... I have left out some of the boilerplate code that comes with HTML5 BoilerPlate.

CSS

/* --------------------------------------------------------------------------
   General Layout
   -------------------------------------------------------------------------- */
html,body {
    height: 100%;
}

body {
    background-color: #e3e3e3;
    color: #696969;
}

#wrapper {
    min-height: 100%;
    width: 100%;
    min-width: 936px;
}

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */
header {
    background-color: #232323;
    height: 108px;
    width: 100%;
    margin: auto;
    padding: 24px 0px 8px 0px;
    position: relative;
}

#header-content {
    height: 100%;
    width: 800px;
    margin: auto;
    position: relative;
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */
footer {
    background-color: #dbdbdb;
    border-top: 1px solid #bababa;
    height: 30px;
    width: 100%;
    min-width: 936px;
    margin-top: -32px;
    position: relative;
}

#footer-content {
    border-top: 1px solid #f8f8f8;
    height: 100%;
    margin: 0px auto;
    position: relative;
}

#footer-content > div {
    width: 800px;
    margin: 0px auto;
}


/* --------------------------------------------------------------------------
   DOWNLOADZONE
   -------------------------------------------------------------------------- */
#dl-info {
    width: 400px;
    margin: auto;
    display: table-cell !important;
    vertical-align: middle;
}

#show-hide {
    margin: 8px 0px;
    text-align: center;
}

/* --------------------------------------------------------------------------
   General helper classes
   -------------------------------------------------------------------------- */
.zone {
    background: none;
    border: 0px none;
    height: 100%;
    min-height: 100px;
    width: 100%;
    padding-top: 140px;
    padding-bottom: 31px;
    display: table;
    position: absolute;
    top: 0px;
    bottom: 0px;
    overflow: hidden;
}

.border {
    border: 1px solid #454545;
}

.clear {
    clear: both;
}


/* Hide from both screenreaders and browsers: h5bp.com/u */
.hidden { 
    display: none !important;
    visibility: hidden;
}

/* Hide only visually, but have it available for screenreaders: h5bp.com/v */
.visuallyhidden { 
    border: 0;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
}

/* Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: h5bp.com/p */
.visuallyhidden.focusable:active, 
.visuallyhidden.focusable:focus { 
    clip: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    position: static;
    width: auto;
}

/* Hide visually and from screenreaders, but maintain layout */
.invisible { visibility: hidden; }

/* Contain floats: h5bp.com/q */
.clearfix:before, 
.clearfix:after { 
    content: "";
    display: table;
}

.clearfix:after { clear: both; }

.clearfix { *zoom: 1; }

​ HTML

<!doctype html>
<!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ -->
<!-- misteroneill.com/improved-internet-explorer-targeting-through-body-classes/ -->
<!--[if lt IE 7]> <html class="no-js ie ie6 lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie ie7 lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie ie8 lt-ie9 lt-ie8" lang="en"> <![endif]-->
<!--[if IE 9]> <html class="no-js ie ie9 lt-ie9" lang="en"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]>
<!-->
<html class="no-js" lang="en">
<!--<![endif]-->
<head>
    <title>Layout</title>
</head>

<body class="select-none">

    <div id="wrapper">

        <header>
            <div id="header-content">
            </div><!-- end #header-content -->
        </header><!-- end header -->

        <div id="downloadzone" class="zone clearfix">

            <div id="dl-info">
                <div class="border">
                    <div id="dl-button">Icon Here</div>
                    <div id="dl-extras">
                        <div id="dl-filename">text text text</div>
                        <div id="show-hide">CLICK TO SHOW/HIDE HIDDEN ELEMENT</div>
                    </div>
                </div>
            </div>

        </div><!-- end #downloadzone -->

    </div><!-- end #wrapper -->

    <footer>
        <div id="footer-content">
            <div class="border-highlight">
            </div><!-- end .border-highlight -->
        </div><!-- end #footer-content -->
    </footer><!-- end footer -->

</body>
</html>
​

If I understand you correctly (my apologies if I'm answering the wrong question here), you want an element of unknown height to be horizontally and vertically centered, with a possible other element beneath it that shouldn't affect the position when it's displayed?

How about using overflow? Here's a demo. I'll put the code here soon.

Compatibility warning: the vertical centering method used will not work in Internet Explorer 7 or lower.

Layout with fixed header and footer, fixed width sidebar and flexible content

9 votes

I'm trying set up a layout that will look like this: enter image description here

I want to use twitter bootstrap for the project, but I understand it may not be the best way to go for the basic layout that looks like this. I know how to setup the header and footer to be fixed at the top and bottom, but I have a hard time having my sidebar constant width and independently scrollable.

My current implementation is here: http://jsfiddle.net/Mwkrw/3/.

I tried setting up the fixed sidebar using Fixed sidebar naviagion in fluid twitter bootstrap 2.0 and a couple of other similar answers on stack overflow, but they all break when the sidebar is longer than the content and as far as I know there is no way to give it an independent scroll.

I would ideally like to do this with pure css - no javascript. I'm sure it's possible and it's my lack of skill and knowledge that prevents me form doing it properly, so there may be no point in unnecessarily adding javascript code. (I'm still adding a javascript tag in case it's not possible)

Thanks for all the help!

EDIT: So my header clearly did not need to be position fixed. Here is the new and improved version: http://jsfiddle.net/Mwkrw/4/ I'm still struggling with the two scrollable divs though.

The magic is in box-sizing:border-box;. For compatibility with Firefox, chrome<10, and safari<5.1, add the -webkit- and -moz- prefixes. IE supports it as of 8.0.

<!doctype html>
<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <title>very structured layout</title>
        <style type='text/css'>
            *      {margin:0; padding:0;}
            body   {background:#fff; position:absolute; width:100%; height:100%;}
            #main  {background:#888; height:100%; padding:60px 0 40px; box-sizing:border-box;}
            #head  {background:#f8f; position:absolute; width:100%; height:60px;}
            #left  {background:#ff8; float:left; width:250px; height:100%; overflow:scroll;}
            #right {background:#8f8; height:100%; overflow:scroll;}
            #foot  {background:#f88; position:absolute; bottom:0; width:100%; height:40px;}​
        </style>
    </head>
    <body>
        <div id='head'>header: width = 100%, height = 40px</div>
        <div id='main'>
            <div id='left'>left: width = 250px, height = 100%</div>
            <div id='right'>right: width = 100% - 250px, height = 100%</div>
        </div>
        <div id='foot'>foot: width = 100%, height = 60px</div>​
    </body>
</html>

fiddle

edit: after Andres' solution made me realize I could achieve greater compatibility, I messed around a bit and came up with an alternate solution, which I think is more intuitive as well. It doesn't work in IE7, but it does work in IE8.

The page is the same as the above, with the only change being that the CSS is replaced with this:

*      {margin:0; padding:0;}
body   {background:#fff;}
#main  {background:#888; position:absolute; top:40px; bottom:60px; width:100%;}
#head  {background:#f8f; position:absolute; width:100%; height:40px;}
#left  {background:#ff8; position:absolute; width:250px; height:100%; overflow:scroll;}
#right {background:#8f8; margin-left:250px; height:100%; overflow:scroll;}
#foot  {background:#f88; position:absolute; bottom:0; width:100%; height:60px;}

fiddle

Note that, for both versions, #head and #foot need to have an overflow property other than visible if their content would otherwise extend off the page.

Table or list: what should I use here?

9 votes

I would like to know which tags I should use for layout like this. Semantically is both a table and a list to me. How I can achieve those underlines and keep the markup right?

enter image description here

I would personally use an ordered list to achieve this, the sub list under Suma skladki means it isn't really tabular data.

This link should give you EXACTLY what you need:

http://thepcspy.com/read/css_table_of_contents/

What does !default in a css property value mean?

9 votes

The twitter bootstrap code has a lot of CSS properties with a !default at the end.

E.g.

p {
  color: white !default;
}

What does !default do?

UPDATE

My bad for not being clear. I am using the SASS port of Bootstrap.

Twitter Bootstrap uses LESS as far as I've seen. On the other hand, !default is actually part of Sass, and is used for giving Sass variables ($var) default values, which would make it invalid in your given context, even in Sass.

Besides, I've not been able to find any references to !default in the LESS documentation, and to my knowledge it is exclusive to Sass. Are you sure you found this in Bootstrap's source and not elsewhere? Because I honestly don't remember seeing Sass/SCSS code in Bootstrap's stylesheets.

For what it's worth, the only valid token that starts with ! in CSS is !important, which you may already be aware of.

Dynamic float layout with CSS

8 votes

Let me try and explain what I want to achieve. I want X boxes with a specific width (250 px) set but dynamic height to be placed in the body. But I want them to be as compact as possible, no unnecessary empty space between them.

Now If all boxes had same width and height, this would be easy. I could for example just put float:left; on them. But the when the boxes height is dynamic, and all boxes have random height I end up with spaces between the boxes.

Let me show two examples:

This is what I want:

This is what I want

This is what I end up with:

This is what I end up with

This is my CSS:

<style type="text/css">
<!--
body {
    background:#CCCCCC;
}
.flowBox {
    background:#FFFFFF;
    margin:10px;
    float:left;
    padding:10px;
    width:250px;
    border:#999999 1px solid;
}
.clear {
    clear:both;
}
-->
</style>

HTML example for a box:

<div class="flowBox">
   <h1>Header 0</h1>
   Erat volutpat. Sed rutr...
</div>

Full source code: http://pastebin.com/UL1Nqyvm

Is there a way to achieve this with CSS? Thanks for any help or directions!

From what I've seen before, what you want to achieve is hardly possible if not impossible with CSS only. What you want, basically, is a layout similar to Pinterest, you can check their website for a reference if you aren't sure what I am talking about.

From here, you can research a bit more into how Pinterest layout was done and if there are any alternatives - CSS Frameworks, jQuery Plugins and so on.

What I found for you from a short search with having the above in mind:

Additionally, here is a short explanation by Evan Sharp who wrote the code for Pinterest layout:

I wrote the Pinterest script. Here's the base of how it works:

Beforehand: Absolutely position the pin containers Determine column width Determine margin between columns (the gutter)

Setup an array: Get the width of the parent container; calculate the # of columns that will fit Create an empty array, with a length equaling the # of columns. Use this array to store the height of each column as you build the layout, e.g. the height of column 1 is stored as array[0]

Loop through each pin: Put each pin in the shortest column at the moment it is added "left:" === the column # (index array) times the column width + margin "top:" === The value in the array (height) for the shortest column at that time Finally, add the height of the pin to the column height (array value)

The result is lightweight. In Chrome, laying out a full page of 50+ pins takes <10ms>

You can go from here by either researching into the topic even further with the slight guidance I have provided or if you are into coding, you could even make your own implementation of the above explanation.

It would be much easier to use the jQuery Plugins though, but if they suit your case that's only for you to decide.

Don't trigger hover event on children

8 votes

I have a container with tiles (grass, water, etc) and in some of them I have items (border-sprites, trees, and general items). Due to the nature of the sprites, all items are 64x64 while tiles are only 32x32.

My problem is that I want to trigger a hover event on tiles, but they are sometimes shadowed by another tiles' items.

The image below shows the problem. The thick green area is the tile that really gets hovered when I want to hover the tree-tile.

the problem

The CSS:

#map_canvas .tile{
    height: 32px;
    position: absolute;
    width: 32px;
}
#map_canvas .tile .item{
    background-position: bottom right;
    background-repeat: no-repeat;
    bottom: 0;
    display: inline-block;
    height: 64px;
    margin: 0;
    padding: 0;
    position: absolute;
    right: 0;
}

The HTML, simplified:

<div class="tile" style="background-image: url(grass.png);"></div>
<div class="tile" style="background-image: url(grass.png);"></div>
<div class="tile" style="background-image: url(grass.png);">
    <div class="item" style="background-image(top-left-border.png);"></div>
</div>

Here's the live demo http://sleavely.com/tiles/

I don't even know how to phrase the question, but here goes:

Is it possible to only trigger the event on the parent element (.tile) so that overflowing children (.item) do not obfuscate which tile I really hover?

EDIT: Thanks to @Brilliand I implemented the following

function figureOutTile(e){
    var $source = jQuery(e.srcElement);
    if($source.hasClass("item")){
        var $parent = $source.parent();
        var posx = $parent.attr("col");
        var posy = $parent.attr("row");
        if(e.offsetY <= 32){
            if(e.offsetX <= 32){
                return jQuery(".tile[col="+ (posx-1) +"][row="+ (posy-1) +"]");
            }else{
                return jQuery(".tile[col="+ posx +"][row="+ (posy-1) +"]");
            }
        }else{
            if(e.offsetX <= 32){
                return jQuery(".tile[col="+ (posx-1) +"][row="+ posy +"]");
            }else{
                return $parent;
            }
        }
    }else{
        return $source;
    }
}
jQuery("#map_viewport").on({
    mouseenter: function(e) {
        var $target = figureOutTile(e);
        $target.addClass('hovered');
    },
    mouseleave: function() {
        jQuery(".tile.hovered").removeClass('hovered');
    }
}, '.tile');​

As far as your browser is concerned, hovering over something sticking out of a tile is the same as hovering over the tile that it's sticking out of, not hovering over whatever is being covered up. To work around this in your specific situation, I suggest putting your hover function on #map_canvas, and working out in that function which tile is being hovered over. For tiles in a rectangular grid, this is simple arithmetic.

Of course, for this to work you will need to include a mousemove event (to detect when the mouse moves from one tile to another), and you should probably include code to exit the function if the user is still hovering over the same tile.

EDIT: Although this answer has already been accepted, here's a solution based on my comment:

$(".tile").append($("<div/>", {
    css: {
        position: "absolute",
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        "z-index": 50
    }
}));

This seems to fix the problem for all of the tiles with items on them, though it screws up your :empty declarations. I mention it mainly because it comes closer to answering your question as asked.

INITIALS - CSS:first-letter over two lines

8 votes

I am trying to create large initials in < p > elements which should start on sencond line and cover two lines but in firefox the first letter is not positioned as I expect (Works everywhere else, even in IE, only FF makes problems...)

http://jsfiddle.net/6SfHG/1/

First letter problem

Any ideas how to make it start on same level?

This has worked for me, though it's not very elegant:

So to get a cross browser drop cap effect using :first-letter pseudo-element that ver­tic­ally aligns, you need to apply float: left, then find the height of the typeface cap height, reduce the line-height to that, adjust margin-top so it aligns cor­rectly in Fire­fox and in Opera or a Web­Kit browser, and then using con­di­tional com­ments for an IE only stylesheet remove margin-top and change line-height to cor­rectly ver­tic­ally align the type.

http://nickcowie.com/2009/drop-caps-first-letter-and-firefox/