Prioritizing Critical CSS with PHP during a request - php

I've read this article, which talks about loading a web page's critical CSS first, and then asynchronously loading other CSS assets once the page has rendered.
Is it possible to use PHP to work out what must be placed in the critical asset file? To my mind, elements like input, textarea, form, table etc, can be loaded later. It's the div, ul, ol, p, hx etc that usually make up the biggest part of the "above the fold" css. Maybe always load these first?
Apart from the most important elements, I'd think the properties that make up the shape of the website are the things that must be loaded first, then the backgrounds and other "paint".
Any good ideas to start with? I'd like to generate and automatically cache the results for website pages automatically and got that all set up. I want to take it a step further with the client-side loading performance, but without too much hassle and extra time during development, while making websites for clients. The framework should do the hard work.
I thought about some smart regexes that would sort it out, but what seems so hard, is the "prioritization"..

Stealing the example from your link. You would put your main styles (div, wrappers, p, images, or any styles for above the fold) in the head to load with the normal way. Once the page loads and runs the script it fires the script to load your css files.
<?php
$cssArray = array('file1.css', 'file2.css', 'file3.css');
?>
<script>
/*!
Modified for brevity from https://github.com/filamentgroup/loadCSS
loadCSS: load a CSS file asynchronously.
[c]2014 #scottjehl, Filament Group, Inc.
Licensed MIT
*/
function loadCSS(href){
var ss = window.document.createElement('link'),
ref = window.document.getElementsByTagName('head')[0];
ss.rel = 'stylesheet';
ss.href = href;
// temporarily, set media to something non-matching to ensure it'll
// fetch without blocking render
ss.media = 'only x';
ref.parentNode.insertBefore(ss, ref);
setTimeout( function(){
// set media back to `all` so that the stylesheet applies once it loads
ss.media = 'all';
},0);
}
<?php
foreach($cssArray as $css) {
print 'loadCss("' . $css . '");'
}
?>
</script>
<noscript>
<!-- Let's not assume anything -->
<?php
foreach($cssArray as $css) {
print '<link rel="stylesheet" href="' . $css . '">'
}
?>
</noscript>
From experience, and best practice, all css calls should be located in your <head> and all script calls should be right before your </body>. All files will load asynchronously to a certain number based on your web server configuration file, normally around 5. Once those files, or one is free, it starts the next file(s)
Automation
This is a whole new host of problems.
Now you will have to load the file and have a set point to stop looking for tags, classes, or id's to check for (using an html parser).
Then you have to load and read your css files to pull out the classes that were found in the previous step.
Output the file to your filesystem in multiple files.
one for first load
others for the javascript method or load at bottom of page
Check the files on creation time, or modified, and remake as needed or call in if they are available
To me this option is two time consuming and can cause problems, and possibly load time decline, if not done properly or you have to process large files. Since most of this work will be done on the server, you wait to get the first byte of data will be longer then just serving them the traditional way.

Related

Simulate PHP Include Without PHP

I want to include the same navigation menu on multiple pages, however I do not have PHP support, nor can I affect my server in any other way.
I want to avoid simply copying and pasting the html onto all the pages as this would make updating the menu a pain.
The two options I can think of are as follows:
1) Have all the content exist on one page, then determine which content to show based on a keyword appended to the url:
example.com/index?home
example.com/index?news
2) Include a javascript file that has a function that writes the menu out and call the function on each page
function setupMenu() {
$("#nav").html("<ul class='nav'><li>home</li><li>news</li></ul>");
}
With Option 1, the updating process would consist of editing one nav menu on the one page
With Option 2, updating would mean changing the function in the javascript file
My concern with Option 1 is that the page would have to load a lot of content that it wouldn't need to display. My concern for Option 2 may seem trivial but it is that the code can get messy.
Are there any reasons doing it one way would be better than the other? Or is there a third superior option that I'm missing?
You have a few options, each with its own advantages and drawbacks:
Server Side Includes, or SSI. If you don't have PHP there's a good chance you don't have SSI either, and this option requires some irritating mucking-about with your .htaccess file. Check Dominic P.'s answer for a writeup of SSI. The benefit of SSI over JavaScript or Frames is that it doesn't require the user to have JS enabled - which a lot of users don't - and it also doesn't present any navigational difficulties.
Frames. You could either use standard frames to put the navigation in its own separate file, and with the correct styling it would be seamless. You could also use an iframe to place your navigation in an arbitrary part of the site, like a sidebar or whatever. The downside to frames, particularly standard frames, is that they tend to make bookmarking, links and the forward/back buttons behave oddly. On the upside, frames don't need browser compliance or server support.
JavaScript. You can refer to any of the other answers for excellent explanations of the JS solution, particularly if you're using jQuery. However, if your site isn't otherwise dynamic enough that your users will want to have JavaScript enabled, this will mean that a large number of your viewers will not see the menu at all - bad, definitely.
-
Yes use .load jQuery ajax function
$('#result').load('ajax/menu.html');
That way your code stays clean, and you can just edit the includes in seperate HTML files just like PHP.
You should consider AJAX for this task. Include a third party library like jQuery and load the separate HTML files inside placeholders, targeting them by ID.
E.g, in your main HTML page:
<div id="mymenu"></div>
Also, in your main HTML, but in the HEAD section:
$('#mymenu').load('navigation.html');
But your best bet would be to switch to a hosting that supports PHP or any other server-side includes. This will make your life a lot easier.
Check out Server Side Includes. I don't have a whole lot of experience with them, but from what I recall, they are designed to be a solution to just your problem.
Server-side includes: http://www.freewebmasterhelp.com/tutorials/ssi/
You can use HTML Imports http://w3c.github.io/webcomponents/spec/imports/
Here is an example from http://www.html5rocks.com/en/tutorials/webcomponents/imports/
warnings.html contains
<div class="warning">
<style scoped>
h3 {
color: red;
}
</style>
<h3>Warning!</h3>
<p>This page is under construction</p>
</div>
<div class="outdated">
<h3>Heads up!</h3>
<p>This content may be out of date</p>
</div>
Then index.html could contain
<head>
<link rel="import" href="warnings.html">
</head>
<body>
...
<script>
var link = document.querySelector('link[rel="import"]');
var content = link.import;
// Grab DOM from warning.html's document.
var el = content.querySelector('.warning');
document.body.appendChild(el.cloneNode(true));
</script>
</body>

Best way to represent CSS & JS files for a big project

What is the best way to represent CSS files for a large project
I am using CodeIgniter and there would be 100's of views and almost of them have different structure so I have a lot of options here but I don't know what is the best one so please help
Make a single file for CSS and single file for JS
Make a CSS file for each view and JS for each view
Make a simple database table to hold the associated files for
each method
for example
id ----- method_name ---- files (I will normalize it )
1 /test/first first.css,first.js
and so on
or make a PHP function get the associated files as text from PHP
for example
<?php
function get_assoc($view)
{
switch($view):
case '/test/first':
echo "<script>alert(); </script><style>p{font-weight:bold;}</style>";
break;
endswitch;
}
?>
Also what about caching? Performance is a big factor.
Thanks.
I like to seperate each section reset/typograpy/forms/tables, this way I dont get lost. Dont be afraid to use as many different files as you need ( for development purposes ).
Once your ready to go into production/live mode, grab the "build tool" from "html5boilerplate" and compress all your css into one file, same for js. This will also minify your code and cache your files. just keep your un-compressed files handy incase you need to do a major edit
<!-- CSS -->
<link rel=stylesheet href="assets/css/reset.css" >
<link rel=stylesheet href="assets/css/typography.css" >
<link rel=stylesheet href="assets/css/tools.css" >
<link rel=stylesheet href="assets/css/tables.css" >
<link rel=stylesheet href="assets/css/forms.css" >
<link rel=stylesheet href="assets/css/plugins.css" >
<!-- Script -->
<script src="assets/js/modernizr2.0.js"></script>
<script src=https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js></script>
<script src="assets/js/plugins.js"></script>
<script src="assets/js/tools.js"></script>
<script src="assets/js/tables.js"></script>
<script src="assets/js/forms.js"></script>
<script src="assets/js/functions.js"></script>
I then like to wrap each (js) file as an object, again this helps with readability.
example:
(function($){
var ToolsObj = {
init : function(){
this.tooltip();
this.tabs();
this.pagination();
this.alerts();
this.dropdowns();
this.lightbox();
},
tooltip : function(){
//tooltip code
},
tabs : function(){
//tabs code
},
pagination : function(){
},
alerts : function(){
//alert messages code
},
dropdowns : function(){
//dropdown-menu code
},
lightbox : function(){
//lightbox code
}
}
$(function(){
ToolsObj.init();
});
})(jQuery.noConflict());
Hope this gives you some insight into my workflow.
You may also want to check if each element exists in the document before running the objects.
Database = no
Don't use the database for this. The CSS/JS files needed to display a view are directly tied to the source code, so keep that info in the source (particularly if you're using an SCM like Git or SVN).
CSS/JS = presentation
As these files are related to presentation/UI, I'd recommend delegating the "responsibility" of loading them to the views themselves. The controllers & models shouldn't have to "know" anything about the CSS/JS required to display the view.
Be modular
Organize the files into discrete modular units. Don't have a separate CSS/JS file for every view UNLESS you truly have completely separate functionality on every single view. The more you share these files among views, the better off you'll be.
Leverage caching, rather than fighting it
I know it's a pain in the ass to rename a file every time you modify it, but it really is a good approach. Using cache invalidating approaches (like URL?time=...) simply puts extra strain on the server and clients for no good reason. Just take the two seconds to rename your "styles.css" file to "styles_v2.css". You'll thank yourself later. (And remember, you don't have to rename it for every single dev change--only when it's stable enough for QA / production).
Premature optimization = root of all evil
Finally--and most importantly--NEVER PREMATURELY OPTIMIZE! I've seen way too many people minify and gzip their asset files all the time, only to have them overhauled a few days later. Either create a true build process, or wait until things stabilize to worry too much about the fine tuning.
Do you already make a page database call to figure out which views should be used etc? May want to have a main js and css that would be used for all pages, then individual ones linked via DB that are specifically used only by certain views.
As for caching... These files will be cached by browsers as long as they have the same request name. I typically auto-version these with a view method that looks something like:
function autoversion($filename) {
$time = filemtime($filename);
return $filename . '?v=' . $time;
}
If you have a build system that can version these files for you, you will get a small performance gain.

Load CSS files using PHP, based on page content

Is this possible? For example, I'm loading all of my css files through my header. One of the things I'm using is the JQuery DataTables plug-in. However, I don't want to load the DataTables css unless the page content contains a DOM element of type "table". I've tried evaluating the page with:
file_get_contents($_SERVER["PHP_SELF"];
Which doesn't work. What's the most efficient way to evaluate your page's content in PHP, and load CSS files appropriately? Or, is javascript a better way to do this?
I would say you're over thinking this.
Set a far away cache expiration date on your DataTable css and simply let the user cache the css file.
This could be done using output buffering, but it sounds like a bad idea to collect the whole document, analyze it, and then add a style sheet header - it's likely to be slow, kludgy and may even hit memory limits in the case of huge tables.
I would tend to say always load the CSS files, and see to it that they're properly cached.
I found it easiest to just set some flags in my parent .php file and have the header file check for those flags and modify output as it gets loaded.
index.php:
<?php
$INCLUDE_TABLE_CSS = true;
include('header.php');
header.php:
blah blah blah
<?php if (isset($INCLUDE_TABLE_CSS) && $INCLUDE_TABLE_CSS) { ?>
<link rel="stylesheet" .... href="table.css" />
<? } ?>
blah blah blah
Unless you've got a large number of conditional settings, then this is fairly simple to manage.
Javascript is a better way to do this. You can do a deferred inclusion, sometimes called "lazy load". Within domready, you would check for the presence of a given class, let's say dataTable. If there are any elements with this class, you inject a new <script> or <link> tag into the header with a reference to the javascript or css file containing the needed script/styles. The <script>/<link> tag's onload event will be the callback to trigger whatever initialization you have to do once the script is in place.
My apologies that I can't tell you the jQuery way (I am a Mootools guy), but in Mootools there is a class called Asset that manages the creation of the <script>/<link> tag and the resulting onComplete event. I'm certain there is a jQuery analog to this.
Use jQuery! This code looks to see if there is a <table>...</table> object, and if there is, it creates a new <link> element with your desired CSS file and adds it to the header object.
if ($('table').length>0){
var link = $("<link>");
link.attr({type: 'text/css', rel: 'stylesheet', href: 'tableStyleSheet.css'});
$("head").append( link );
}

Multiple javascript/css files: best practices?

I have about 7 Javascript files now (thanks to various jQuery plugins) and 4-5 CSS files. I'm curious as to what's the best practice for dealing with these including where in the document they should be loaded? YSlow tells me that Javascript files should be--where possible--included at the end. The end of the body? It mentions that the delimeter seems to be whether they write content. All my Javascript files are functions and jQuery code (all done when ready()) so that should be OK.
So should I include one CSS and one Javascript file and have those include the rest? Should I concatenate all my files into one? Should I put Javascript my tags at the very end of my document?
Edit: FWIW yes this is PHP.
I would suggest using PHP Minify, which lets you create a single HTTP request for a group of JS or CSS files. Minify also handles GZipping, Compression, and HTTP Headers for client side caching.
Edit: Minify will also allow you to setup the request so that for different pages you can include different files. For example a core set of JS files along with custom JS code on certain pages or just the core JS files on other pages.
While in development include all the files as you normally would and then when you get closer to switching to production run minify and join all the CSS and JS files into a single HTTP request. It's really easy to setup and get working with.
Also yes, CSS files should be set in the head, and JS files served at the bottom, since JS files can write to your page and can cause massive time-out issues.
Here's how you should include your JS files:
</div> <!-- Closing Footer Div -->
<script type="application/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.1.min.js"></script>
</body>
</html>
Edit: You can also use Cuzillion to see how your page should be set up.
Here's what I do: I use up to two JavaScript files and generally one CSS file for each page. I figure out which JS files will be common across all of my pages (or enough of them so it's close - the file containing jQuery would be a good candidate) and then I concatenate them and minify them using jsmin-php and then I cache the combined file. If there are any JS files left over that are specific to that one page only, I concatenate, minify, and cache them into a single file as well. The first JS file will be called over a number of pages, the second only on that one or maybe a few.
You can use the same concept with CSS if you like with css-min, though I find I usually only use one file for CSS. One thing extra, when I create the cache file, I put in a little PHP code in the beginning of the file to serve it as a GZipped file, which is actually where you'll get most of your savings anyways. You'll also want to set your expiration header so that the user's browser will have a better chance of caching the file as well. I believe you can also enable GZipping through Apache.
For the caching, I check to see if the file creation time is older than the amount of time that I set. If it is, I recreate the cache file and serve it, otherwise I just get the existing cached file.
You haven't explicitly said that you've got access to a server-side solution, but assuming you do, I've always gone with a method involving using PHP to do the following:
jquery.js.php:
<?php
$jquery = ($_GET['r']) ? explode(',', $_GET['r']) : array('core', 'effects', 'browser', 'cookies', 'center', 'shuffle', 'filestyle', 'metadata');
foreach($jquery as $file)
{
echo file_get_contents('jquery.' . $file . '.js');
}
?>
With the snippet above in place, I then call the file just like I normally would:
<script type="text/javascript" src="jquery.js.php"></script>
and then if I'm ever aware of the precise functionality I'm going to need, I just pass in my requirements as a query string (jquery.js.php?r=core,effects). I do the exact same for my CSS requirements if they're ever as branched.
I would not recommend using a javascript based solution (like PHP Minify) to include your css as your page will become unusable if the visitor has javascript disabled.
The idea of minifying and combining the files is great.
I do something similar on my sites but to ease development I suggest some code which looks like this:
if (evironment == production) {
echo "<style>#import(/Styles/Combined.css);</style>"
} else {
echo "<style>#import(/Styles/File1.css);</style>"
echo "<style>#import(/Styles/File2.css);</style>"
}
This should let you keep your files separate during dev for easy management and use the combined file during deployment for quicker page loads. This assumes you have the ability to combine the files and change variables as part of your deploy process.
Definitely look into including your js at the bottom and the css at the top as per YUI recommendations as keeping the JS low has a tangible affect on the appearance of the rest of the page and feels much faster.
I also tend to copy+paste all of my jquery plugins into a single file: jquery.plugins.js then link to
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js">
for the actual jquery library.

How can I cycle through pages?

Here's a challenge that I was tasked with recently. I still haven't figured out the best way to do it, maybe someone else has an idea.
Using PHP and/or HTML, create a page that cycles through any number of other pages at a given interval.
For instance, we would load this page and it would take us to google for 20 seconds, then on to yahoo for 10 seconds, then on to stackoverflow for 180 seconds and so on an so forth.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Dashboard Example</title>
<style type="text/css">
body, html { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; }
iframe { border: none; }
</style>
<script type="text/javascript">
var Dash = {
nextIndex: 0,
dashboards: [
{url: "http://www.google.com", time: 5},
{url: "http://www.yahoo.com", time: 10},
{url: "http://www.stackoverflow.com", time: 15}
],
display: function()
{
var dashboard = Dash.dashboards[Dash.nextIndex];
frames["displayArea"].location.href = dashboard.url;
Dash.nextIndex = (Dash.nextIndex + 1) % Dash.dashboards.length;
setTimeout(Dash.display, dashboard.time * 1000);
}
};
window.onload = Dash.display;
</script>
</head>
<body>
<iframe name="displayArea" width="100%" height="100%"></iframe>
</body>
</html>
Use a separate iframe for the content, then use Javascript to delay() a period of time and set the iframe's location property.
When you are taken to another site (e.g. Google) control passes to that site, so in order for your script to keep running, you'd need to load the new site in a frame, and keep your script (which I'd imagine could most readily be implemented using Javascript) in another frame (which could be made very small so you can't see it).
I managed to create this thing. It's not pretty but it does work.
<?php
# Path the config file, full or relative.
$configfile="config.conf";
$tempfile="tmp.html";
# Read the file into an array
$farray=file($configfile);
# Count array elements
$count=count($farray);
if(!isset($_GET['s'])){
$s=0;
}else{
$s=$_GET['s'];
if($s==($count-1)){ # -1 because of the offset in starting our loop at 0 instead of 1
$s=0;
}else{
$s=$_GET['s']+1; # Increment the counter
}
}
# Get the line from the array
$entry=$farray[$s];
# Break the line on the comma into 2 entries
$arr=explode(",",$entry);
# Now each line is in 2 pieces - URL and TimeDelay
$url=strtolower($arr[0]);
# Check our url to see if it has an HTTP prepended, if it doesn't, give it one.
$check=strstr($url,"http://");
if($check==FALSE){
$url="http://".$url;
}
# Trim unwanted crap from the time
$time=rtrim($arr[1]);
# Get a handle to the temp file
$tmphandle=fopen($tempfile,"w");
# What does our meta refresh look like?
$meta="<meta http-equiv=\"refresh\" content=\"".$time.";url=index.php?s=".$s."\">\n";
# The iframe to display
$content="<iframe src =\"".$url."\" height=\"100%\" width=\"100%\"></iframe>";
# roll up the meta and content to be written
$str=$meta.$content;
# Write it
fwrite($tmphandle,$str);
# Close the handle
fclose($tmphandle);
# Load the page
die(header("Location:tmp.html"));
?>
Config files looks like (URL, Time to stay on that page):
google.com,5
http://yahoo.com,10
Depends on your exact requirements. If you allow JavaScript and allow frames then you can stick a hidden frame within a frameset on your page into which you load some JavaScript. This JavaScript will then control the content of the main frame using the window.location object and setTimeout function.
The downside would be that the user's address bar would not update with the new URL. I'm not sure how this would achievable otherwise. If you can clarify the constraints I can provide more help.
Edit - Shad's suggestion is a possibility although unless the user triggers the action the browser may block the popup. Again you'd have to clarify whether a popup is allowable.
Create a wrapper HTML page with an IFrame in it, sized at 100% x 100%. Then add in some javascript that changes the src of the IFrame between set intervals.
I think it would have to work like gabbly.com, which sucks in other websites and displays them with its own content over it.
Once you read the other site in and were ready to display it, you couldn't really do it "in PHP"; you would have to send an HTML redirect meta-tag:
<meta HTTP-EQUIV="REFRESH" content="15; url=http://www.thepagecycler.com/nextpage.html">
Or you could use Javascript instead of the meta-tag.
This is not doable in a PHP script, unless you want to edit the redirect.... PHP is a back end technology; you're going to need to do this in Javascript or the like.
The best you're going to do, as far as I know, is to create a text file on your web server and load a different HTTP address based on time out of that text file, then redirect the browser to the site found in that text file.
The first solution that jumps to mind is to do this in a frameset. Hide one of the frames, and the other display the pages in question. Drive the page transitions with Javascript from the hidden frame.
function RefreshFrame()
{
parent.VisibleFrame.location.href = urlArray[i];
i++;
if(i < urlArray.length) SetTimeout("RefreshFrame()", 20000);
}
var i = 0;
var urlArray = ['http://google.com','http://yahoo.com', 'http://www.search.com'];
RefreshFrame();
In this example the Javascript would be in the hiddend frame, and you would name your visible frame "VisibleFrame".
Disclaimer: I just wrote this code in the comment window and have not tested it
You could do this with JavaScript quite easily. It would help to know the deployment environment. Is it a kiosk or something?
For the JavaScript solution, serve up a page that contains a JavaScript that will pop open a new browser window. The controller page will then cause the new browser window to cycle through a series of pages. That's about the simplest way to do this that I can think of.
Edit: Agree with Simon's comment. This solution would work best in a kiosk or large, public display environment where the pages are just being shown without any user interaction.
The theory behind the request is basically the ability to cycle through web page dashboards for various systems from a "kiosk" PC. I oversee a data center and we have several monitor systems that allow me view dashboards for temps, system up time, etc etc.
The idea is load a page that would cycle from dashboard to dashboard remaining on each for an amount of time specified by me, 1 minute on this board, 30 seconds on the next board, 2 minutes on the next and so on.. Javascript is absolutely allowable (though I have little experience with it). My mediums of choice are PHP/HTML and I'm not seeing a way to make this happen cleanly with just them..
There's a bunch of ways you can do this, iv written several scripts and tools with everything from JS to Ruby
In the end It was much easier to use http://dashboardrotator.com . It handled browser restarts, memory allocation and accidental window closure for me with a nice simple GUI.

Categories