Should we append custom CSS after the default CSS in layout.html?

149 views
Skip to first unread message

Anthony

unread,
Aug 3, 2013, 9:44:35 AM8/3/13
to web2py-d...@googlegroups.com
In layout.html, should we replace this:

{{  
  response
.files.append(URL('static','css/web2py.css'))
  response
.files.append(URL('static','css/bootstrap.min.css'))
  response
.files.append(URL('static','css/bootstrap-responsive.min.css'))
  response
.files.append(URL('static','css/web2py_bootstrap.css'))
}}

with this:

{{response.files = [URL('static', 'css/%s.css' % file) for file in
     
['web2py', 'bootstrap.min', 'bootstrap-responsive.min', 'web2py_bootstrap']] + response.files}}

That way users' custom css files will come after the bootstrap/web2py css files, making it easier to override the default styles.

Anthony

Paolo Caruccio

unread,
Aug 3, 2013, 11:04:14 AM8/3/13
to web2py-d...@googlegroups.com
Yes we should.


1) Include external CSS files before external JavaScript files
2) Do not include inline JavaScript between external CSS and other resources

The first consequence of this is a web2py_ajax rewritten and to place it in <head> section before stylesheets.
 
We should consider also that jquery and bootstrap files may be downloaded from CDN repositories.

Niphlod

unread,
Aug 3, 2013, 12:11:06 PM8/3/13
to web2py-d...@googlegroups.com
TBH I never got myself to like even the fact that bootstrap.js is placed at the end of the page.
Anyway, Anthony's is a good proposition for not-so-accustomed users in the need of overriding something.

Also, having css files lined up before js is good, but I'm not so sure I'd want that figured out automatically of a misorganized list of response.files at every web request....users in the need can very well tweak the response.files list in the correct order. As such, even considering public or private CDNs should be left to the user: I surely don't want to have a crippled application when I need to develop offline or where internal policy reasons does not allow me to reach a CDN.

tl;dr : as any other things in web2py, a sane default has to be provided, the rest should be left to the users. I surely don't want to figure out for every combination a smart parallel loader (hey, google reccomendation, they are even speedier) even if that would be the smartest thing to provide to an application. The general web2py population of users can of course benefit by the fact that custom css are indeed appended instead of prepended, but I'm not sure they are ready to fiddle with loading parallelism unless properly informed.


On Saturday, August 3, 2013 5:04:14 PM UTC+2, Paolo Caruccio wrote:
Yes we should.

Paolo Caruccio

unread,
Aug 4, 2013, 5:04:46 AM8/4/13
to web2py-d...@googlegroups.com
Now web2py doesn't serve files in optimal order. We could accomplish a better result by removing from web2py_ajax.html 

{{
response
.files.insert(0,URL('static','js/jquery.js'))
response
.files.insert(1,URL('static','css/calendar.css'))
response
.files.insert(2,URL('static','js/calendar.js'))
response
.files.insert(3,URL('static','js/web2py.js'))
response
.include_meta()
response
.include_files()
}}

and by rewriting the <head> in layout.html in this way

<head>
<title>{{=response.title or request.application}}</title>
 
<!--[if !HTML5]>
      <meta http-equiv="X-UA-Compatible" content="IE=edge{{=not request.is_local and ',chrome=1' or ''}}">
  <![endif]-->

 
<!-- www.phpied.com/conditional-comments-block-downloads/ -->
 
<!-- Always force latest IE rendering engine
       (even in intranet) & Chrome Frame
       Remove this if you use the .htaccess -->

   
 
<meta charset="utf-8" />




 
<!-- http://dev.w3.org/html5/markup/meta.name.html -->
 
<meta name="application-name" content="{{=request.application}}" />




 
<!-- Speaking of Google, don't forget to set your site up:
       http://google.com/webmasters -->

 
<meta name="google-site-verification" content="" />




 
<!--  Mobile Viewport Fix
        j.mp/mobileviewport & davidbcalhoun.com/2010/viewport-metatag
        device-width: Occupy full width of the screen in its current orientation
        initial-scale = 1.0 retains dimensions instead of zooming out if page height > device height
        user-scalable = yes allows the user to zoom in -->

 
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
 
  {{response.include_meta()}}




 
<link rel="shortcut icon" href="{{=URL('static','images/favicon.ico')}}" type="image/x-icon">
 
<link rel="apple-touch-icon" href="{{=URL('static','images/favicon.png')}}">




  {{include 'web2py_ajax.html'}}
 
 
<!-- include stylesheets -->
  {{# default stylesheets
  response.files.insert(0, URL('static','css/web2py.css'))
  response.files.insert(1, URL('static','css/bootstrap.min.css'))
  response.files.insert(2, URL('static','css/bootstrap-responsive.min.css'))
  response.files.insert(3, URL('static','css/web2py_bootstrap.css'))
  response.files.insert(4, URL('static','css/calendar.css'))
  }}
  {{# user stylesheets (css extension)
  # response.files.append (custom_file)
  }}


 
<!-- include javascripts -->
  {{# default javascript
  response.files.append(URL('static','js/modernizr.custom.js'))
  response.files.append(URL('static','js/jquery.js'))
  response.files.append(URL('static','js/web2py.js'))
  response.files.append(URL('static','js/calendar.js'))
  }}
  {{# user javascripts (js extension)
  # response.files.append (custom_file)
  }}
 
  response.include_files()
 
   
<!-- uncomment here to load jquery-ui
       <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/base/jquery-ui.css" type="text/css" media="all" />
       <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js" type="text/javascript"></script>
       uncomment to load jquery-ui //-->

 
<noscript><link href="{{=URL('static', 'css/web2py_bootstrap_nojs.css')}}" rel="stylesheet" type="text/css" /></noscript>
 
  {{
  # using sidebars need to know what sidebar you want to use
  left_sidebar_enabled = globals().get('left_sidebar_enabled',False)
  right_sidebar_enabled = globals().get('right_sidebar_enabled',False)
  middle_columns = {0:'span12',1:'span9',2:'span6'}[
    (left_sidebar_enabled and 1 or 0)+(right_sidebar_enabled and 1 or 0)]
  }}
{{block head}}{{end}}
</head>

We should change also def include_files() in gluon.globals in order to give the right priority: inline css, inline script, external css, external js, external resources

About CDN, you are right but my reasoning is based on the fact that nowadays we develop code primarily online and web2py would benefit from using CDN resources. But this is my guess.

Niphlod

unread,
Aug 4, 2013, 5:30:53 AM8/4/13
to web2py-d...@googlegroups.com
please don't.
We can reorder all the css and the js (first css, then js, then any user's appended files) in web2py_ajax.html and then let the users fiddle with their own append order.
To do what you're trying to do means wasting CPU at runtime just to filter out an unordered list of files, and since we don't provide response.include_files_js() and response.include_file_css() but just response.include_files(), lets leave things uncomplicated. 
BTW, this reorganization will "speed up" just the first load of an app, cause subsequent request will fetch the cached files (that should be anyone's first concern, not reordering files :-P).

PS: modernizr should be the only script loaded before everything else and included in layout.html instead of web2py_ajax.html, else you may get FOUC between the page load and modernizr applying classes to the body element.

Paolo Caruccio

unread,
Aug 5, 2013, 7:07:27 PM8/5/13
to web2py-d...@googlegroups.com
Assuming that
1) although the files caching is important, as well as their compression, 
the order in which the files are served is also important 
(even after the first upload when the files are cached). 
Based on the W3C standards, in fact, the style sheets have to be inserted in the <head>
of the html page, and in order to improve the performance of the page loading 
- according to the majority of developers - javascript files should be placed 
in the bottom of the page before closing <body> tag. The precedence of the 
files having the same extension, it is also important especially for css files 
that are applied when read by engine browsers, but also for the javascript 
files that link to other libraries;
2) the function include_files() already allows to distinguish the files according to their extension;
3) web2py serves default static files and these can be directly inserted (by CDN or not)
in the correct sequence within layout.html without calling the include_files function and thus reducing the load of the processor;
4) dynamic insertion of other static files should be, in my opinion, only by response.files.insert/append inside the controller or 
better in the views that need it before {{extend ...}}, avoiding to use <script> tag
but creating an appropriate js file and calling it with include_files into the right positions in layout.html;
5) web2py_ajax should contain only functions/variables related to ajax

I packed a test "welcome" app (attached) which has better performance than the current (results from http://www.webpagetest.org/ either first load and cached) without modifying web2py core files.

About Modernizr to avoid FUOC it must be in the <head> but after the style sheets. However, I think - but I may be wrong - that web2py does not use css rules based on Modernizr.
web2py.app.welcome1.w2p

Massimo DiPierro

unread,
Aug 6, 2013, 3:09:07 AM8/6/13
to web2py-d...@googlegroups.com
The main change of your welcome app seems to be that in the layout this code is put at the bottom:

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="http://code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script src="{{=URL('static','js/calendar.js')}}"></script>
<script src="{{=URL('static','js/web2py.js')}}"></script>
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.m\
in.js"></script>
<script src="{{=URL('static','js/web2py_bootstrap.js')}}"></script>

I do not oppose using <script src="{{=URL('static','js/calendar.js')}}"></script> instead of {{response.insert(...,URL('static','js/calendar.js'))}} except that if users do not see it there there may not see it anywhere.

I do have some concerns
- <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script> should be <script src="{{=URL('static','js/jquery.js')}}"></scirpt> else it does not work offline
- <script src="http://code.jquery.com/jquery-migrate-1.2.1.min.js"></script> why?
- Inline jQuery will not work anymore. I agree it should be discouraged but some jQuery plugins use inline jQuery as examples and we making more difficult for users to use those plugins.

Massimo

Niphlod

unread,
Aug 6, 2013, 9:06:07 AM8/6/13
to web2py-d...@googlegroups.com
I'm not a big fan of regression tests (especially web-based), but really, you should give numbers and comparisons to support this. Any "webpagetest.org" test has issues that crimple speed tests in so many ways you can't control that saying "it's faster" is not going to reassure me :P

I slightly modified your app to match at least the same jquery version of the standard welcome app as it is right now, and skipped the jquery compatibility module to be as fair as I could.

Please note I'm not criticizing what you're trying to do, but I'm just trying to figure out what "counters" to observe to match the "speed improvement" that I should notice

Now, a few observations from your tests.....
First big issue: cdn. You can't really test the speed between a page served all from one server and with something loaded from a cdn.
Second (little issue): even if we'd accept to use CDNs (and I'm totally NOT up for it), https with jquery works only from microsoft and google's cdn, not with the code.jquery.com domain
Third: please forgive my total lack of "lets see what counters to look at" but at least locally with firebug your app has an onload time of 30-40ms less than the default welcome (of course not the first load, cause localhost beats CDN), but for some reason 70-150ms higher than the default one with all static files gzipped.

in this light, I'm just up to reorganize the default welcome app to put js first than css (right now its backwards), but just because it's "recommended" as I can't observe any speed difference with the tools at my toolbelt.

tl;dr: I don't know where to look for speed improvements because putting all in head vs leaving js at the bottom seems to not give any performance benefit.
On a totally different note (other counter, but still something to look to), your version of the welcome app takes on my pc 4-8 ms more to generate the markup, reaching 20-22ms vs 16-18ms of the standard one.

Paolo Caruccio

unread,
Aug 6, 2013, 11:34:32 AM8/6/13
to web2py-d...@googlegroups.com
I'm sorry for my poor clarity (my English sucks) but the app was a simple test to demonstrate the benefits coming from a riorganization of how the static files (css and js) are served (not only for timing) and not to compare point to point the current strategy adopted by web2py due to proved reasons. For this I used in my test app cdn resources (http/https no matter in this test case) and last jQuery (line 1.x) while web2py doesn't. I used webpagetest.org in order to have a platform to calculate a benchmark indipendently from my enviroment but we could use another one that has less issues. Maybe http://speed.webstatzone.com
Anyway my argumentation is founded on best practices suggested to improve the performance of a web site. Most of html/css/js frameworks apply the structure I indicated (css on top and js on bottom). For example html5 boilerplate index.html  (https://github.com/h5bp/html5-boilerplate), twitter bootstrap  (http://getbootstrap.com/getting-started/#template), foundation (https://github.com/zurb/foundation/blob/master/templates/project/index.html), backbone boilerplate (https://github.com/backbone-boilerplate/backbone-boilerplate/blob/master/index.html).
Moreover searching in the net we will found a bunch of articles on how improve web site performance (for example https://developers.google.com/speed/articles/, http://developer.yahoo.com/yslow/) which suggest the structure I said.
In conclusion my previous post is academic not a proposal change. I think that by exchanging ideas we will end to find a way to improve web2py. 

@Massimo
for more details on jquery-migrate plugin please see https://github.com/jquery/jquery-migrate/#readme

Massimo DiPierro

unread,
Aug 6, 2013, 11:37:57 AM8/6/13
to web2py-d...@googlegroups.com
On Aug 6, 2013, at 10:34 AM, Paolo Caruccio wrote:

I'm sorry for my poor clarity (my English sucks) but the app was a simple test to demonstrate the benefits coming from a riorganization of how the static files (css and js) are served (not only for timing) and not to compare point to point the current strategy adopted by web2py due to proved reasons. For this I used in my test app cdn resources (http/https no matter in this test case) and last jQuery (line 1.x) while web2py doesn't. I used webpagetest.org in order to have a platform to calculate a benchmark indipendently from my enviroment but we could use another one that has less issues. Maybe http://speed.webstatzone.com
Anyway my argumentation is founded on best practices suggested to improve the performance of a web site. Most of html/css/js frameworks apply the structure I indicated (css on top and js on bottom). For example html5 boilerplate index.html  (https://github.com/h5bp/html5-boilerplate), twitter bootstrap  (http://getbootstrap.com/getting-started/#template), foundation (https://github.com/zurb/foundation/blob/master/templates/project/index.html), backbone boilerplate (https://github.com/backbone-boilerplate/backbone-boilerplate/blob/master/index.html).
Moreover searching in the net we will found a bunch of articles on how improve web site performance (for example https://developers.google.com/speed/articles/, http://developer.yahoo.com/yslow/) which suggest the structure I said.
In conclusion my previous post is academic not a proposal change. I think that by exchanging ideas we will end to find a way to improve web2py. 

@Massimo
for more details on jquery-migrate plugin please see https://github.com/jquery/jquery-migrate/#readme


I understand this but we are not proposing that users of old web2py apps upgrade to jQuery 1.9+. Yet for new apps they should use jQuery 1.9+. Web2py does not need migrate. Do we want to encourage using legacy jQuery plugins or code for newly developed apps?

Massimo

Il giorno martedì 6 agosto 2013 15:06:07 UTC+2, Niphlod ha scritto:
I'm not a big fan of regression tests (especially web-based), but really, you should give numbers and comparisons to support this. Any "webpagetest.org" test has issues that crimple speed tests in so many ways you can't control that saying "it's faster" is not going to reassure me :P

I slightly modified your app to match at least the same jquery version of the standard welcome app as it is right now, and skipped the jquery compatibility module to be as fair as I could.

Please note I'm not criticizing what you're trying to do, but I'm just trying to figure out what "counters" to observe to match the "speed improvement" that I should notice

Now, a few observations from your tests.....
First big issue: cdn. You can't really test the speed between a page served all from one server and with something loaded from a cdn.
Second (little issue): even if we'd accept to use CDNs (and I'm totally NOT up for it), https with jquery works only from microsoft and google's cdn, not with the code.jquery.com domain
Third: please forgive my total lack of "lets see what counters to look at" but at least locally with firebug your app has an onload time of 30-40ms less than the default welcome (of course not the first load, cause localhost beats CDN), but for some reason 70-150ms higher than the default one with all static files gzipped.

in this light, I'm just up to reorganize the default welcome app to put js first than css (right now its backwards), but just because it's "recommended" as I can't observe any speed difference with the tools at my toolbelt.

tl;dr: I don't know where to look for speed improvements because putting all in head vs leaving js at the bottom seems to not give any performance benefit.
On a totally different note (other counter, but still something to look to), your version of the welcome app takes on my pc 4-8 ms more to generate the markup, reaching 20-22ms vs 16-18ms of the standard one.

--
-- mail from:GoogleGroups "web2py-developers" mailing list
make speech: web2py-d...@googlegroups.com
unsubscribe: web2py-develop...@googlegroups.com
details : http://groups.google.com/group/web2py-developers
the project: http://code.google.com/p/web2py/
official : http://www.web2py.com/
---
You received this message because you are subscribed to the Google Groups "web2py-developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web2py-develop...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Paolo Caruccio

unread,
Aug 6, 2013, 12:19:36 PM8/6/13
to web2py-d...@googlegroups.com
I will try to explain my personal point of view about to use or not new versions of jQuery and bootstrap although the matter is OT referred to the subject of this thread.
In this days I'm writing for a funny test (repeat "funny test") a welcome application based on jQuery 2 and bootstrap 3 (nowadays RC1) and there are several difficulties that discourage now the migration of web2py. But, in the near future we will have to found a solution because the web development is migrating on the mobile, dropping the support to old browsers. One of the most important feature of web2py is the backward compatibility and I think that we have to make core program more independent from external resources. In this way the user will choice which jQuery version or css framework apply. For example we should rewrite the code generating html making it more flexible by setting variable css classes. In the few days I hope to publish on web2py user group the mentioned app highlighting the difficulties encountered.
Reply all
Reply to author
Forward
0 new messages