Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
352 lines (310 sloc) 12.7 KB
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>responsivepx - find that tricky breakpoint</title>
<!-- Feel free to fork on github too: https://github.com/remy/responsivepx -->
<link rel="shortcut icon" type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAANCAYAAACdKY9CAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAZpJREFUeNqUUb9LQmEUfb+fPn8gDpFogRCIgoSgS0MgbQ1CEQ3tRQRhQtDa2lTRWHMtRUu0Zf+A4BKCk0RDBJqiPsWnvtc5ouDaB4d73rnnu/e79ym5XO670+m84+yl0+mgqqqbw+HwUcAB3wF/LZVKv9ls9t7n82WlYDC4GAqFdjOZzJosyxuRSOQO3lWCnBpz9NArVSqVc0mS5HA4XNR1/dDlcumO4ywR5NSYo4deka1TqdRxNBq9higCQrVa3aIei8WebdsWAKdWq+XL5fKNkkwmTwzDKPR6PQfVJgVGo5HCOBgMhGl04DmFV1ZwO+52u5cpAvZ4PLYty/qisdlsjjCDBCrS02q14sJ/j4JNrGN9+3NaDx3OSDRNu0AwZgms+FYRRTHv9Xq356vU6/UXRugH8zqeZCgY9qjf7795PJ5LdNKmlVRG6LPKlmmaBaz6SWo0Gj/oUsDwWrfbNbkZbGkCcmrM0UOvFAgEPvGx0m63i6hyNb0wJsipMUcPvYLf77fwnA+2xp9NYN8PiAvElCeYo4fePwEGAFJa2ZbVKf+5AAAAAElFTkSuQmCC">
<style>
body { font-family: sans-serif; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACcAAAAnCAYAAACMo1E1AAAAcUlEQVRYCe3TsQ0AIQzFUGCD7L9jMgIwAJUVOlMiGZ2e/s3M3KPxRETba6vtpQ8P+XEUVTnlqADt3JxyVIB2bk45KkA7N6ccFaDd3PfQ+NVV1esa3flDILYbKaccFaCdm1OOCtDOzSlHBWjn5pSjArQ7Dl0LEgUi4pIAAAAASUVORK5CYII=); margin: 0; padding: 0; }
input { font-size: 16px; padding: 2px; font-family: sans-serif; }
input[type=number] { width: 60px; }
input[type=range] { width: 100px; height: 7px; }
iframe.viewport { background: #fff; position: width: 100%; margin: 34px auto 0 auto; display: block; height: 2000px; -webkit-box-shadow: 0 5px 80px #505050; }
form { height: 30px; overflow: hidden; display: block; background: #333; background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#666666), to(#666666), color-stop(.6,#333)); color: #fff; width: 100%; padding: 2px; position: fixed; top: 0; left: 0; border-bottom: 1px solid rgba(0, 0, 0, .15); }
form {
text-shadow: 0 -1px 1px #000;
}
#info {
width: 50%;
margin: 15% auto 0;
box-shadow: 0 5px 80px #505050;
-webkit-box-shadow: 0 5px 80px #505050;
-moz-box-shadow: 0 5px 80px #505050;
-o-box-shadow: 0 5px 80px #505050;
-ms-box-shadow: 0 5px 80px #505050;
background: #fff;
padding: 40px;
line-height: 1.4em;
}
#info h1 {
margin-top: 0;
}
#info p:last-child {
margin-bottom: 0;
}
#share {
text-decoration: none;
color: #fff;
border: 2px solid transparent;
padding: 2px 4px;
}
#share:hover {
text-decoration: none;
color: #fff;
border: 2px inset rgba(0, 0, 0, .15);
background: rgba(0, 0, 0, 0.1);
border-radius: 3px;
}
#share:active {
background: rgba(0, 0, 0, 0.4);
color: #ddd;
}
</style>
</head>
<body>
<form>
<input placeholder=http:// value=http:// id=url name=url autocomplete autofocus spellcheck=false autocapitalize=off autocorrect=off>
<input type=submit value=Open>
<span title="Because I can't determine programatically whether the scrollbars are visible, you need to check this box yourself to adjust the pixel value to give the real viewport width - rather than the window width">Scrollbar visible? <input type=checkbox id=scrollbars checked></span>
Width: <select id=width step=1 type=range>
<option>10</option>
<option>340</option>
<option>480</option>
<option selected>640</option>
<option>800</option>
<option>960</option>
<option>1024</option>
<option>1920</option>
<option>2048</option>
<option>3000</option>
</select>
<!-- <input type=range id=width step=1 min=10 max=3000 value=640> -->
<input size=4 type=number min=10 step=1 class=width>
Height:
<select id=height step=1 type=range>
<option>10</option>
<option>340</option>
<option selected>480</option>
<option>640</option>
<option>800</option>
<option>960</option>
<option>1024</option>
<option>1920</option>
<option>2048</option>
<option>3000</option>
</select>
<!-- <input type=range step=1 id='height' step=10 min=100 max=3000 value=640> -->
<input size=4 type=number min=10 step=1 class=height>
<a title='Open a new email with the permalink to this breakpoint' href='mailto:?subject=responsivepx.com' id=share>Share</a>
</form>
<div id="info">
<h1>About responsivepx</h1>
<p>Enter the url to your site - local or online: both work - and use the controls to adjust the width and height of your viewport to find exact breakpoint widths in pixels. Then use that information in your media queries to create a <a href="http://www.alistapart.com/articles/responsive-web-design/">responsive design</a>.</p>
<p>Watch the <a target="_new" href="http://www.youtube.com/watch?v=kYpENMubJKQ">video explaining usage</a> and why it was built.</p>
<p>If your site appears with scrollbars, make sure to check the scrollbar visible box to get the right viewport width and height.</p>
<p>Fork the project or log an issue on <a href="http://github.com/remy/responsivepx">github</a></p>
<p>Built by <a href="http://twitter.com/rem">@rem</a></p>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script>
/**
* This was from a proposal that James Edwards / Brothercake had during
* 2011 Highland Fling - to use select elements as a starting point for
* the range element - so it's a pretty darn good fit, I put this together
* during his Q&A. In the end I needed to lift the detection code from
* Modernizr - which credit really goes to @miketaylr.
* My code starts from "if (bool) {"
*
* This code is looking for <select type="range"> and will progressively
* enhance to a input[type=range] copying much of the attributes across.
*/
!function () {
var rangeTest = document.createElement('input'),
smile = ':)';
rangeTest.setAttribute('type', 'range');
var bool = rangeTest.type !== 'text';
if (bool) {
rangeTest.style.cssText = 'position:absolute;visibility:hidden;';
rangeTest.value = smile;
if (rangeTest.style.WebkitAppearance !== undefined ) {
document.body.appendChild(rangeTest);
defaultView = document.defaultView;
// Safari 2-4 allows the smiley as a value, despite making a slider
bool = defaultView.getComputedStyle &&
defaultView.getComputedStyle(rangeTest, null).WebkitAppearance !== 'textfield' &&
// Mobile android web browser has false positive, so must
// check the height to see if the widget is actually there.
(rangeTest.offsetHeight !== 0);
document.body.removeChild(rangeTest);
}
} else {
bool = rangeTest.value == smile;
}
// if the input[range] is natively supported, then upgrade the <select type="range">
// into a range element.
if (bool) {
function firstChild(el, nodeName) {
nodeName = nodeName.toUpperCase();
if (el.firstChild.nodeName === nodeName) {
return el.firstChild;
} else {
return el.firstChild.nextSibling;
}
}
function lastChild(el, nodeName) {
nodeName = nodeName.toUpperCase();
if (el.lastChild.nodeName === nodeName) {
return el.lastChild;
} else {
return el.lastChild.previousSibling;
}
}
var selects = document.getElementsByTagName('select'),
i = 0;
for (; i < selects.length; i++) {
if (selects[i].getAttribute('type') == 'range') (function (select) {
var range = document.createElement('input'),
parent = select.parentNode;
range.setAttribute('type', 'range');
// works with the select element removed from the DOM
select = parent.replaceChild(range, select);
range.autofocus = select.autofocus;
range.disabled = select.disabled;
range.autocomplete = select.autocomplete; // eh? how would this even work?
range.className = select.className;
range.id = select.id;
range.style = select.style;
range.tabindex = select.tabindex;
range.title = select.title;
range.min = firstChild(select, 'option').value;
range.max = lastChild(select, 'option').value;
range.value = select.value;
// yeah, this is filth, but it's because getElementsByTagName is
// a live DOM collection, so when we removed the select element
// the selects object reduced in length. Freaky, eh?
i--;
})(selects[i]);
}
}
}();
</script>
<script>
// workout what the dimensions of a scrollbar is for the particular browser.
// It's usually 15px, but who sersiously trusts browsers nowadays?!
function calcScrollbarWidth() {
var el = $('<div style="overflow: scroll;">').appendTo('body')[0];
var offset = el.offsetHeight;
el.parentNode.removeChild(el);
return offset;
}
function newframe(url) {
$('iframe').remove();
$('<iframe frameborder=0 class="viewport" src="' + url + '"></iframe>').css('display', 'none').appendTo('body').one('load', function () {
// this is just to prevent the initial iframe from appearing empty (as it has a shadow)
$(this).css('display', 'block');
});
}
function addhistory() {
if (history.pushState && url) {
clearTimeout(historyTimer);
historyTimer = setTimeout(function () {
history.pushState(null, null, '?' + encodeURIComponent(url) + '#' + $w.val() + 'x' + $h.val() + (useoffset ? '&scrollbars' : ''));
}, 500);
}
}
function size(w, h, nohistory) {
// ensure the values are numbers
w *= 1;
h *= 1;
if (!nohistory) addhistory();
// adjust for whether we have the scrollbars visible
$('iframe').width(w + (useoffset ? offset : 0)).height(h + (useoffset ? offset : 0));
}
var win = $('iframe'),
$w = $('#width'),
$h = $('#height'),
offset = calcScrollbarWidth(),
useoffset = $('#scrollbars').is(':checked'),
$url = $('#url'),
$hide = $('#hide'),
$form = $('form'),
$range = $('[type=range]'), // done on purpose
historyTimer = null,
url = '';
$form.submit(function (e, nohistory) {
e.preventDefault();
$('#info').remove();
// allows me to keep things nice and friendly on the url
var newurl = url = $url.val();
if (newurl.indexOf('://') === -1) newurl = 'http://' + newurl;
if (url.indexOf('http://') === 0) url = url.substr(7); // strip the http:// part - don'ts needs'it
newframe(newurl);
$range.trigger('change', nohistory); // I realise this triggers the size function twice - I'm just lazy :)
});
$('#share').click(function () {
var copy = '';
if (!url) {
copy = 'Check out this tool for finding breakpoints in responsive designs:\n\nhttp://' + location.host;
} else {
copy = 'See these breakpoints in ' + url + ':\n\nhttp://' + location;
}
this.href = 'mailto:?body=' + encodeURIComponent(copy);
});
$('#scrollbars').click(function () {
useoffset = this.checked;
var w = $('iframe').width() - (useoffset ? offset : 0),
h = $('iframe').height() - (useoffset ? offset : 0);
addhistory();
$('input[type=number], [type=range]').each(function () {
if (this.id == 'width' || this.className == 'width') {
this.value = w;
} else {
this.value = h;
}
});
});
$('input[type=number]').bind('input', function (e, nohistory) {
$('#' + this.className).val(this.value);
size($w.val(), $h.val(), nohistory);
}).bind('keydown', function (e) {
if (e.shiftKey) {
this.step = 10;
} else { // I could test here, but the cost of the DOM action would outweigh the cost of the optimisation
this.step = 1;
}
});
$range.bind('change', function (e, nohistory) {
$('.' + this.id).val(this.value);
size($w.val(), $h.val(), nohistory);
}).bind('click', function () {
$(this).focus();
});
if (window.top !== window.self) window.top.location.replace(window.self.location.href);
if (history.pushState) {
window.onpopstate = function () {
// read the location and reload
var settings = location.hash.substr(1).split('&');
if (settings.length == 2) {
useoffset = true;
$('#scrollbars').attr('checked', 'checked');
} else if (location.hash) {
useoffset = false;
$('#scrollbars').removeAttr('checked');
}
if (settings[0].indexOf('x') !== -1) { // if it actually has some value
var wh = settings[0].split('x');
$w.val(wh[0]);
$h.val(wh[1]);
}
$('input.width').val($w.val());
$('input.height').val($h.val());
var newurl = decodeURIComponent(location.search.substr(1));
if (newurl !== url) {
$url.val(newurl);
$form.trigger('submit', [ true ]); // tell the form not to add to the history
} else {
$range.trigger('change', [ true ]);
}
};
}
var _gaq = [['_setAccount', 'UA-1656750-27'], ['_trackPageview']];
(function(d, t) {
var g = d.createElement(t),
s = d.getElementsByTagName(t)[0];
g.async = g.src = '//www.google-analytics.com/ga.js';
s.parentNode.insertBefore(g, s);
}(document, 'script'));
</script>
</body>
</html>
Something went wrong with that request. Please try again.