CSS Sprites (was Wanted: New feature ideas for GSOC projects)
We talked about css sprites last year with Louis St-Amour when he considered taking a GSOC project about new customisable theme in http://moodle.org/mod/forum/discuss.php?d=93163#p418987
Most likely it can't be done with pure css alone - you need to make changes to a couple of core files too but the idea is worth testing - it is also connected to http://moodle.org/mod/forum/discuss.php?d=116398
All kinds of theme projects are fun and useful... some students might be interested in testing editor skins (for coming moodle 2.0 and tinymce) or to modify some single activities instead of large theme projects.
$icon = "$CFG->modpixpath/$mod->modname/icon.gif";
are the problem to implement this kind of method. Maybe we can isolate the files that are used this way and the ones that could be used in sprites.
<img src="allimages.png" class="edit" />
<img src="allimages.png" class="down-3-right-2" />
<img src="allimages.png" style="????" /> -- (what is ??? anyway?)
Anyway, I guess this means you need to coordinate three things: CSS in the CSS files, the contents of the png, and the code that outputs the icon. That it OK, it can all go in the theme. I have alywas thought we needed a function to output icons. I hate having that code duplicated everywhere.
Oh, and what do you do when it needs to be <input type="image" ... />?
No - not to img tags. We can use sprites without any img tags - we only need for example ul and li tags, we need to use class or id to get correct position for icon from css file (in this case class) and in fact those classes are already there...
For example in weblib.php
$menu[] = '<li class="'.$class.'">'.
'<img src="'.$CFG->modpixpath.'/'.$mod->modname.'/icon.gif" alt="" />'.
'<a href="'.$CFG->wwwroot.'/mod/'.$url.'">'.$mod->name.'</a></li>';
gives a icon link where class is given with previous code $class = 'activity '.$mod->modname; $class .= ($cmid == $mod->cm) ? ' selected' : '';
Unfortunately <ul> has no class but we could take away all those img tags and use css to render icons according to li class and even add hover effects to links.
It looks difficult at first look but might be possible to set up anyway - and creating those sprites means just collecting single icons to one image and checking the positions of each left top corner of each image... some switch might still be useful to allow old themes to use separate images instead of sprite.
So the basic idea is that if we have in html file
<li id="panel2b"><a href="#"></a></li>
the background image (sprite) of whole <ul> can be given in css - background: url(test.jpg); - and position of background image of li id="panel2b" can be given with
#panel2b {left: 96px; width: 75px;}
and hover effect of the link inside that li tag can be given in css for example with
#panel2b a:hover {background: transparent url(test.jpg) -96px -200px no-repeat;}
Another good point is that we could allow any size and type of images in menus - icons don't need to be 16x16 - themes could as well set different sizes and add different effects to menus.
One more great link - http://www.alistapart.com/articles/sprites2
<img src=".../edit.gif" alt="Edit" />
or
<input type="image" src=".../edit.gif" alt="Edit" />
going to sprites would involve going to non-semantic HTML, and in the second case, requiring JavaScript. I can't say I am jumping up and down with excitement at the idea.
Well we are talking about different thing - why does moodle use img tags for icons after all? Anywhere?
We don't need any img tags in menus - in any menus - all styling could be done with theme css if we have different classes or ids for divs or li tags. It would allow using images with background property. It is of course possible to hide all img icons with css (display:none) but it is also possible to add other type of effects to divs and li tags if those icons are not there... and to create totally different kind of menus.
I think it is possible to test both sprites and other menu styles as GSOC projects and see if it requires any major changes to core code - maybe it's easier than I first thought.
The former could be done with sprites, the latter needs to be img/input in the HTML.
Hmm, except that activity types and file types are both open-ended lists. If you want to use sprites, what will happen if you install a new module?
And is this really the lowest hanging fruit in the field of Moodle performance?
We don't need to change everything or change all icons - but we may test some new ideas like this.
According to YAHOO it really makes difference if you use sprites or don't use them
http://css-tricks.com/css-sprites-what-they-are-why-theyre-cool-and-how-to-use-them/
http://developer.yahoo.com/performance/rules.html#num_http
I think we don't loose anything if we test sprites in some cases like
http://alt-web.com/CSS-Sprite-Demo.html
http://dev.opera.com/articles/view/31-css-background-images/#sprites
and if it looks good we can implement some changes to core code.
Just wanted to clarify that Javascript wouldn't be necessary unless you're wanting images to change on rollover events and such.
I ran a test on this as a non-editing teacher loading a random course page. There were 26 HTTP image requests! This should certainly be slimmed down with sprites.
Additional modules and block icons would probably need to be handled the same way they have been, but basically any icon associated with themes could be "sprited".
Not necessarely - that's why I added the last link in previous post
http://blog.josh420.com/archives/2008/07/using-sprite-images-with-input-typeimage-for-hover-effect.aspx and the demo button is in
http://blog.josh420.com/examples/InputImageSprites/
On the other hand I'm sure many designers would love to use javascripts, flash etc together with css to create all kinds of menu effects but that's another story.
We really have many kinds of code in lib files for images/icons in moodle - and different kinds of (possible) ways to use sprites. Those hover effects are common in menus, "image map" style sprites are used in all modern editors to render both normal icons and hover icons - and since first sprites were used in 2004 lots of experimental sites have been testing sprites for various purposes.
Last year when we discussed about custom themes with Louis I was like Tim now - I tried to find pieces of code that make using sprites impossible. Yesterday I tried to find pieces of code that make using sprites possible and tomorrow I will most likely test these with some experimental themes.
Cases like new modules could use default position in sprite that is given first in css for all (li) tags - and if theme does not use icons at all no css for any activities are needed. For example in buttons of tinymce it is possible to define icon also in plugin code with old tinymce 2 style as separate gif image if no css is given for sprite. TinyMCE changed all standard icons to sprite in 2007.
And some simple ideas are just smart - like this one from Google.com
http://learningtheworld.eu/2008/better-foreground-sprites/
Using sprites in foreground images (img tags) might be possible too
http://www.askapache.com/css/speedy-sites-with-image-sprites-and-css.html
but some browsers like IE may not like foreground image sprites or you may need different code / css for IE - yet that's not new...
Traditional method is to use background images anyway.
This may be an interesting project for students. Learning how to use this technique and trying to apply it to Moodle.
I already tested two methods to course icons and they both worked very well in standard theme. For example a very small modification to course/lib.php and replacing
<img src="'.$icon.'" class="activityicon" alt="" />
with
<div class="iconsp icon'.$mod->modname.'"></div>
allows common css for all these icons and default icon with class iconsp and separate position and possible other configuration with class icon+name of the activity - and hover icon! Or it is possible to forget all those icons and use other effects for that div. The link text to activity does not change - it's given after this div with <span>'.$instancename.$altname.'</span> like before.
Css looked like
.iconsp {
background: url(icons.gif);
float: left;
width: 16px;
height: 16px;
margin: 3px 5px 0 0;
}
.iconsp {
background-position: 0 0;
}
a:hover .iconsp {
background-position: 0 -16px;
}
.iconforum {
background-position: -16px 0;
}
a:hover .iconforum {
background-position: -16px -16px;
}
.icondata {
background-position: -32px 0;
}
a:hover .icondata {
background-position: -32px -16px;
}
... and so on.
The other test code was using traditional ul - li modification with different span for icon and link text.
The only bad thing is that I took that img tag away and replaced it with another version of code - a really tiny change but...
At least files weblib.php, course/lib.php, course/modedit.php and blocks/block_activity_modules use icons and sprites could be used for any other images but the optional solution should allow editing css from each theme without a need to modify any code of core files... only theme files. And if some changes are made to standard theme most custom themes can use the same features or people can copy the changed code from standard theme.
I might test one more thing - using 1x1px transparent icon.gif files (activity icons) together with sprite code given with current classes in ul and li tags in custom theme. It does not make number of http requests smaller but allows testing of sprites for effects without need to change the old themes that use 16x16px icons or current core code. At least loading 1x1px images is faster than loading 16x16px images - and after this it is easy to test if taking all icon img tags away makes pages faster (the real influence of those HTTP requests from all separate icon.gif files)
Maybe it's better to check first all possible tricks that we can do in custom themes.
Final test done - I will try to keep my hands off sprites now...
I tried the previous idea with Patrick's Autumn theme that has a lot of icons in mod folder and I made a simple test sprite just for testing and replaced all icon.gif files with 1x1px transparent gif file.
Activity icons worked as expected with hover effects although leaving and using of those img tags is not the best way to use sprites. Anyway if moodle has in source code a tag like
<ul class="section img-text">
<li class="activity forum" id="module-1"><a class="dimmed" href="http://localhost/m19/mod/forum/view.php?id=1"><img src="http://localhost/m19/theme/autumn/pix/mod/forum/icon.gif" class="activityicon" alt="" /> <span>News forum</span></a></li>
we could take as well that img tag to sprite tag and first create the default icon for all activities with css like
li.activity img{
background: url(icons.gif);
float: left;
width: 16px;
height: 16px;
background-position: aapx bbpx;
}
li.activity a:hover img {
background-position: ccpx ddpx;
}
and then give other backgrounds and hover effects for other activities if we want to use different icons and hover effects with css like
li.forum img {
background-position: eepx ffpx;
}
li.forum a:hover img {
background-position: ggpx hhpx;
}
li.data img {
background-position: iipx jjpx;
}
li.data a:hover img {
background-position: kkpx llpx;
}
and so on...
(...and this example does not mean that we should use img tags for sprites - we should not. )
I don't test these sprites further right now - let's see if some GSOC students are interested.
Urs and Tim have big challenges in
http://docs.moodle.org/en/Development:Theme_engines_for_Moodle%3F
and
http://docs.moodle.org/en/Development:Very_flexible_block_system_proposal
and this is not so urgent project after all. A simple variable, function or what ever switch might be useful to allow some optional code (divs, spans, li:s etc) and otherwise old style image code. Meanwhile I will test other interesting projects...
Thank you for suggesting the project, David!
And sprites could be used for other than course pages too - for example the main page of moodle.org ... http://analyze.websiteoptimization.com gave the following report
Web Page Speed Report
URL: | http://moodle.org |
---|---|
Title: | Moodle.org: open-source community-based tools for learning |
Date: | Report run on Sat Mar 7 05:02:16EST2009 |
Diagnosis
Global Statistics
Total HTTP Requests: | 46 |
Total Size: | 112421 bytes |
Object Size Totals
Object type | Size (bytes) | Download @ 56K (seconds) | Download @ T1 (seconds) |
---|---|---|---|
HTML: | 6992 | 1.59 | 0.24 |
HTML Images: | 45999 | 11.37 | 2.44 |
CSS Images: | 17967 | 7.18 | 3.70 |
Total Images: | 63966 | 18.55 | 6.14 |
Javascript: | 39098 | 9.79 | 2.21 |
CSS: | 2365 | 1.67 | 1.21 |
Multimedia: | 0 | 0.00 | 0.00 |
Other: | 0 | 0.00 | 0.00 |
External Objects
External Object | QTY |
---|---|
Total HTML: | 1 |
Total HTML Images: | 11 |
Total CSS Images: | 18 |
Total Images: | 29 |
Total Scripts: | 10 |
Total CSS imports: | 6 |
Total Frames: | 0 |
Total Iframes: | 0 |
Download Times*
Connection Rate | Download Time |
---|---|
14.4K | 96.33 seconds |
28.8K | 52.77 seconds |
33.6K | 46.54 seconds |
56K | 31.61 seconds |
ISDN 128K | 16.06 seconds |
T1 1.44Mbps | 9.80 seconds |
*Note that these download times are based on the full connection rate for ISDN and T1 connections. Modem connections (56Kbps or less) are corrected by a packet loss factor of 0.7. All download times include delays due to round-trip latency with an average of 0.2 seconds per object. With 46 total objects for this page, that computes to a total lag time due to latency of 9.2 seconds. Note also that this download time calculation does not take into account delays due to XHTML parsing and rendering.
Page Objects
QTY | SIZE# | TYPE | URL | COMMENTS | |
---|---|---|---|---|---|
1 | 14220 | SCRIPT | http://moodle.org/lib/overlib/overlib.js | Header size = 307 bytes Congratulations! This file was compressed. |
|
1 | 7329 | SCRIPT | http://moodle.org/theme/moodle2/sm/c_smartmenus.js | Header size = 306 bytes Congratulations! This file was compressed. |
|
1 | 6992 | HTML | http://moodle.org | Header size = 697 bytes Congratulations! This file was compressed. View a formatted version of this HTML file |
|
1 | 6917 | IMG | mp.moodle.com ... file.php/moodle/block.gif | Header size = 400 bytes | |
1 | 5936 | IMG | http://moodle.org/theme/moodle2/pix/community.gif | Header size = 271 bytes Missing width attribute. Missing height attribute. |
|
1 | 5533 | CSS IMG | moodle.org ... odle2/pix/pix/list_bg.jpg | Header size = 553 bytes | |
1 | 5488 | IMG | moodle.org ... odle2/pix/development.gif | Header size = 271 bytes Missing width attribute. Missing height attribute. |
|
1 | 5342 | IMG | moodle.org ... odle2/pix/moodle-logo.gif | Header size = 271 bytes Missing width attribute. Missing height attribute. |
|
1 | 4934 | IMG | http://moodle.org/theme/moodle2/pix/download.gif | Header size = 271 bytes Missing width attribute. Missing height attribute. |
|
1 | 4617 | IMG | http://moodle.org/theme/moodle2/pix/about.gif | Header size = 271 bytes Missing width attribute. Missing height attribute. |
|
1 | 4394 | IMG | http://moodle.org/theme/moodle2/pix/support.gif | Header size = 271 bytes Missing width attribute. Missing height attribute. |
|
1 | 4128 | SCRIPT | http://moodle.org/lib/javascript-static.js | Header size = 306 bytes Congratulations! This file was compressed. |
|
1 | 3652 | SCRIPT | http://moodle.org/lib/ufo.js | Header size = 306 bytes Congratulations! This file was compressed. |
|
1 | 3612 | SCRIPT | http://moodle.org/lib/speller/spellChecker.js | Header size = 306 bytes Congratulations! This file was compressed. |
|
1 | 3548 | IMG | http://moodle.org/theme/moodle2/pix/news.gif | Header size = 271 bytes Missing width attribute. Missing height attribute. |
|
2 | 3297 | CSS IMG | http://moodle.org/theme/standard/pix/tab/right.gif | Header size = 271 bytes | |
1 | 2730 | CSS IMG | moodle.org ... d/pix/tab/right_hover.gif | Header size = 271 bytes | |
1 | 2345 | SCRIPT | http://moodle.org/lib/overlib/overlib_cssstyle.js | Header size = 306 bytes Congratulations! This file was compressed. |
|
1 | 1947 | IMG | moodle.org ... le2/pix/moodle-logo-1.gif | Header size = 271 bytes Missing width attribute. |
|
1 | 1876 | SCRIPT | http://moodle.org/theme/moodle2/sm/c_config.js | Header size = 306 bytes Congratulations! This file was compressed. |
|
1 | 1869 | IMG | http://moodle.org/images/opensource.gif | Header size = 271 bytes Missing width attribute. Missing height attribute. |
|
1 | 1526 | CSS IMG | moodle.org ... /pix/background_grd_1.jpg | Header size = 272 bytes | |
1 | 1018 | CSS | http://moodle.org/theme/moodle2/styles_ie6.css | Header size = 288 bytes Congratulations! This file was compressed. View a formatted version of this CSS file |
|
1 | 1007 | IMG | http://moodle.org/pix/i/rss.gif | Header size = 271 bytes Missing width attribute. Missing height attribute. |
|
1 | 1000 | SCRIPT | http://moodle.org/lib/dropdown.js | Header size = 306 bytes Congratulations! This file was compressed. |
|
1 | 923 | CSS IMG | http://moodle.org/theme/moodle2/pix/menu_grad.jpg | Header size = 271 bytes | |
1 | 916 | SCRIPT | http://moodle.org/lib/cookies.js | Header size = 305 bytes Congratulations! This file was compressed. |
|
1 | 826 | CSS IMG | moodle.org ... /pix/background_rev_1.jpg | Header size = 271 bytes | |
2 | 541 | CSS IMG | moodle.org ... pix/box_bright_orange.png | Header size = 270 bytes | |
1 | 525 | CSS | http://moodle.org/theme/moodle2/styles_ie7.css | Header size = 287 bytes Congratulations! This file was compressed. View a formatted version of this CSS file |
|
1 | 399 | CSS | http://moodle.org/theme/standard/styles_ie6.css | Header size = 287 bytes Congratulations! This file was compressed. View a formatted version of this CSS file |
|
1 | 392 | CSS IMG | moodle.org ... ix/header_stripe_grad.jpg | Header size = 271 bytes | |
1 | 383 | CSS | http://moodle.org/theme/standard/styles_ie7.css | Header size = 287 bytes Congratulations! This file was compressed. View a formatted version of this CSS file |
|
2 | 315 | CSS IMG | http://moodle.org/theme/moodle2/pix/navbar_bg.jpg | Header size = 271 bytes | |
2 | 293 | CSS IMG | http://moodle.org/theme/standard/pix/tab/left.gif | Header size = 270 bytes | |
1 | 292 | CSS IMG | moodle.org ... rd/pix/tab/left_hover.gif | Header size = 270 bytes | |
2 | 291 | CSS IMG | moodle.org ... 2/pix/bt_right_orange.png | Header size = 270 bytes | |
1 | 289 | CSS IMG | moodle.org ... odle2/pix/bb_right_bg.png | Header size = 270 bytes | |
1 | 270 | CSS IMG | http://moodle.org/theme/moodle2/pix/bb_left_bg.png | Header size = 270 bytes | |
1 | 269 | CSS IMG | moodle.org ... ndard/pix/tab/tabrow1.gif | Header size = 270 bytes | |
2 | 60 | CSS IMG | moodle.org ... /pix/bt_right_8_white.gif | Header size = 244 bytes | |
1 | 60 | CSS IMG | moodle.org ... 2/pix/bt_left_8_white.gif | Header size = 244 bytes | |
1 | 60 | CSS IMG | moodle.org ... 2/pix/bb_left_8_white.gif | Header size = 244 bytes | |
1 | 20 | CSS | http://moodle.org/theme/standard/styles.php | Header size = 300 bytes Congratulations! This file was compressed. View a formatted version of this CSS file |
|
1 | 20 | CSS | http://moodle.org/theme/moodle2/styles.php | Header size = 298 bytes Congratulations! This file was compressed. View a formatted version of this CSS file |
|
1 | 20 | SCRIPT | http://moodle.org/lib/javascript-mod.php | Header size = 305 bytes Congratulations! This file was compressed. |
|
46 ^ | 112421* | Total (^unique objects) |
# Congratulations. This site is using HTTP compression, otherwise called content encoding using gzip. The sizes reported here are for compressed content sent from the server to the client.
* CSS alternate stylesheets may be referenced in the HTML but are not actually downloaded until they are needed and are therefore not included in the total page size.
Analysis and Recommendations
- TOTAL_HTML - Congratulations, the total number of HTML files on this page (including the main HTML file) is 1 which most browsers can multithread. Minimizing HTTP requests is key for web site optimization. Y
- TOTAL_OBJECTS - Warning! The total number of objects on this page is 46 which by their number will dominate web page delay. Consider reducing this to a more reasonable number. Above 20 objects per page the overhead from dealing with the actual objects (description time and wait time) accounts for more than 80% of whole page latency. See Figure II-3: Relative distribution of latency components showing that object overhead dominates web page latency in Website Optimization Secrets for more details on how object overhead dominates web page latency. Combine, refine, and optimize your external objects. Replace graphic rollovers with CSS rollovers to speed display and minimize HTTP requests. Consider using CSS sprites to help consolidate decorative images. Using CSS techniques such as colored backgrounds, borders, or spacing instead of graphic techniques can reduce HTTP requests. Replace graphic text headers with CSS text headers to further reduce HTTP requests. Finally, consider optimizing parallel downloads by using different hostnames or a CDN to reduce object overhead.
- TOTAL_IMAGES - Warning! The total number of images on this page is 29 , consider reducing this to a more reasonable number. Recommend combining, replacing, and optimizing your graphics. Replace graphic rollover menus with CSS rollover menus to speed display and minimize HTTP requests. Consider using CSS sprites to help consolidate decorative images. Use CSS techniques such as colored backgrounds, borders, or spacing instead of graphic techniques to reduce HTTP requests. Replace graphic text headers with CSS text headers to further reduce HTTP requests. Finally, consider optimizing parallel downloads by using different hostnames to reduce object overhead.
- TOTAL_CSS - Warning! The total number of external CSS files on this page is 6 , consider reducing this to one or two external files. Combine, refine, and optimize your external CSS files. Ideally you should have one (or even embed CSS for high-traffic pages) on your pages. You can optimize CSS files using shorthand properties, grouping, and then minify and GZIP compress them to reduce their footprint. Remember to place CSS files in the HEAD and JavaScript files at the end of the BODY to enable progressive display.
- TOTAL_SIZE - Caution. The total size of this page is 112421 bytes, which will load in over 20 seconds on a 56Kbps modem - or 31.61 seconds on a 56Kbps modem. Consider reducing total page size to less than 100K to achieve sub 20 second response times on 56K connections. Be sure to provide feedback for pages over 100K by layering your design to display useful content within the first two seconds. Consider optimizing your site with Website Optimization Secrets, Speed Up Your Site or contacting us about our optimization services.
- TOTAL_SCRIPT - Warning! The total number of external script files on this page is 10 , consider reducing this to a more reasonable number. Combine, refactor, and minify to optimize your JavaScript files. Ideally you should have one (or even embed scripts for high-traffic pages) on your pages. Consider suturing JavaScript files together at the server to minimize HTTP requests. Placing external JavaScript files at the bottom of your BODY, and CSS files in the HEAD enables progressive display in XHTML web pages.
- HTML_SIZE - Congratulations, the total size of this HTML file is 6992 bytes, which less than 50K. Assuming that you specify the HEIGHT and WIDTH of your images, this size allows your HTML to display content in under 10 seconds, the average time users are willing to wait for a page to display without feedback.
- IMAGES_SIZE - Caution. The total size of all your images is 63966 bytes, which exceeds 50K. Consider optimizing and creatively cropping your images, and combining them where appropriate. Even better, replace graphic text and form controls with styled text to eliminate unnecessary HTTP requests. Ideally each image should be less than 1160 bytes, to easily fit into one TCP-IP packet.
- SCRIPT_SIZE - Warning! The total size of external your scripts is 39098 bytes, which is over 20K. Consider optimizing your JavaScript for size, combining them, and using HTTP compression where appropriate for any scripts placed in the HEAD of your documents. You can substitute CSS menus for JavaScript-based menus to minimize or even eliminate the use of JavaScript.
- CSS_SIZE - Congratulations, the total size of your external CSS is 2365 bytes, which is less than 8K.
- MULTIM_SIZE - Congratulations, the total size of all your external multimedia files is 0 bytes, which is less than 10K.