Skip to content

Instantly share code, notes, and snippets.

@esprehn
Last active August 29, 2015 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save esprehn/096f84778871590ed683 to your computer and use it in GitHub Desktop.
Save esprehn/096f84778871590ed683 to your computer and use it in GitHub Desktop.
Fun with FOUC
See the attached test case for an example where Firefox, Chrome/Safari and
old Opera (12) all differ.
1. cd to a directory of files.
2. Run `ruby fouc-server.rb`.
Now the directory will be served on localhost:8000 on your machine,
the directory is also served on localhost:8000/slow and supports a
?delay={seconds} query parameter to cause artificial network delay on that
resource.
ex. localhost:8000/slow/test.css?delay=0.5 will load the test.css file from
the root directory but with a delay of half a second.
3. Write test cases combining various resources, delays, and scripts to
try to cause FOUC.
4. Look at blink with printfs and a debugger to understand our fouc
prevention. Try looking at traces and the inspector timeline as well.
5. Try other browsers too!
Note: You can pass a port number to the fouc-server.rb like
`ruby fouc-server.rb 8500` if you need to use a different port.
#!/usr/bin/env ruby
# Starts a web server for the current directory serving files on / and
# also on /slow/ where the /slow can accept a delay={float seconds}
# ex. /slow/test.css?delay=0.5 for 500ms of delay.
#
# Can accept a single command line argument {port}.
# ruby fouc-server.rb 1234 to start the server on port 1234.
require "webrick"
class SlowFileHandler < WEBrick::HTTPServlet::FileHandler
def service(request, response)
duration = request.query["delay"].to_f
if duration
puts "Sleeping for #{duration}"
sleep duration
end
request.path.sub!(/^\/slow/, "")
super request, response
end
end
def main
port = (ARGV[0] or 8000).to_i
server = WEBrick::HTTPServer.new(:Port => port, :DocumentRoot => Dir.pwd)
file_handler_config = WEBrick::Config::FileHandler.merge({
:FancyIndexing => true,
})
server.mount "/slow", SlowFileHandler, Dir.pwd, file_handler_config
["INT", "TERM"].each do |signal|
trap(signal) do
server.shutdown
end
end
server.start
end
if __FILE__ == $0
main()
end
<!DOCTYPE html>
<!--
Try to cause fouc using offsetTop and setTimeout.
== Results ==
Firefox: Shows the FOUC message, the offsetTop seems to make them
start painting.
Safari/Chrome: No FOUC.
Old Opera (12): Fouc after a few seconds, the offsetTop has no effect,
it seems old Opera will only block painting on a
resource for a few seconds (about 2ish) before resuming
painting even if it would cause FOUC.
-->
<script>
// While <script> will not run while waiting on css to load other
// scheduled script like setTimeout will continue to run so spam
// setTimeout waiting for the parser to block on the <script> at the end
// of the page then trigger a layout to try to cause FOUC. :)
var stopPumping = false;
var timer = 0;
function pump() {
// Poll for the test element to show up.
var test = document.getElementById("test");
if (test) {
document.body.offsetTop;
return;
}
if (!stopPumping)
timer = setTimeout(pump, 0);
}
pump();
</script>
<link rel="stylesheet" href="/slow/test.css?delay=5">
<p id="test">
Should not see <span>this FOUC message that is hidden!??</span>.
</p>
<script>
// This script won't run until the test.css file is loaded.
stopPumping = true;
clearTimeout(timer);
console.log("loaded");
</script>
/* Hide the FOUC message. */
span { color: white; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment