Turning scripts off and on based on Media Queries? - javascript

I am using a widget in my layout and I have it now so when a certain breakpoint is hit it will not display that larger widget and then goes to the smaller one. The larger widget does hide and the smaller one shows up but the text that is associated with both isn't right.
The text for the large widget displays and the smaller text for the small widget doesn't. I am pretty sure it has to do with the scripts each are using. The display none does hide the elements but the scripts seem to be still running.
I have absolutely no clue about JavaScript yet and would prefer a HTML or CSS answer if possible. If not then I will go with JS but will need some direction please. I have read numerous articles and even in the process of learning JS but still not sure how some of what I've read applies.
#media all and (max-width: 900px) {
// styles
}
if (document.documentElement.clientWidth < 900) {
// scripts
}
This is what I've found that seems like it is what I need but I'm not sure on the syntax of how to call the script I need. Do I just put the script itself in there without any other information? I have also read about using jquery to do this with something like this
$(window).resize(function() {
if ($(this).width() > 480) {
// call supersize method
}
});
And I've even read about using Modernizer to do this but I still have to go through the documentation.
In the bin it doesn't show any of the text at all but the larger text is there and off to the side of the small widget. I just need to shut that large script off and turn the other on at a certain media query.
Any help is greatly appreciated.
HTML
<aside class="smallScreen">
<div class="smallWeather" style='width: 200px; height: 440px; background-image:
url(http://vortex.accuweather.com/adcbin/netweather_v2/backgrounds/red_500x440_bg.jpg
); background-repeat: no-repeat; background-color: #993333;' ><div
id='NetweatherContainer' style='height: 420px;' ><script src='http://...'></script>
</div></div></aside>
</div></div></div></aside>
<aside class="largeScreen">
<div class="largeWeather" style='width: 500px; height: 440px; background-image:
url(http://vortex.accuweather.com/adcbin/netweather_v2/backgrounds/red_500x440_bg.jpg
); background-repeat: no-repeat; background-color: #993333;' ><div
id='NetweatherContainer' style='height: 420px;' ><script src='http://...'></script>
</div></div></aside>
CSS
#media screen and (min-width: 564px) and (max-width: 604px) {
.largeScreen {
display: none;
}
.smallScreen {
display: block;
width: 55%;
min-width: 240px;
height: 100%;
font-size: 0;
margin-left: auto;
margin-right: auto;
margin-bottom: 1.2rem;
}
.smallWeather {
position: relative;
display: block;
width: 240px;
height: 420px;
background: white;
margin-left: auto;
margin-right: auto;
}
What is the best way to do this and why please? Is jQuery the best way from a mobile performance standpoint?
UPDATE: Going to use enquire.js because of it's straightforward approach (although I'm still a bit sketchy on it's use) and how small it is.
This is the basic code:
enquire.register("screen and (max-width: 605px)", {
// OPTIONAL
// If supplied, triggered when a media query matches.
match : function() {},
// OPTIONAL
// If supplied, triggered when the media query transitions
// *from a matched state to an unmatched state*.
unmatch : function() {},
// OPTIONAL
// If supplied, triggered once, when the handler is registered.
setup : function() {},
// OPTIONAL, defaults to false
// If set to true, defers execution of the setup function
// until the first time the media query is matched
deferSetup : true,
// OPTIONAL
// If supplied, triggered when handler is unregistered.
// Place cleanup code here
destroy : function() {}
});
Still not done and looking for more support with this. Now that I've chose this route, I see that there is quite a few articles and questions already about enquire.js. I will update my situation as I read up.
UPDATE: This is where I'm at but it's not working yet. I have the styles associated with each script still in the HTML and display none used accordingly. Will doing this work once I get the enquire.js correct?
Here is the new jsbin
Thanks again for everything!!

I think you are looking for something like enquire.js, which is a lightweight JavaScript library for responding to CSS media queries.
If you don't want to use a library, this post on reacting to media queries in JavaScript runs through a way of doing what you are after with vanilla JavaScript.
Here's a jsFiddle Demo with some working example code, and here's a Fullscreen jsFiddle Demo, which is handy when trying to test how it works. If you use the fullscreen version and make the browser window less than 600px wide, a javascript alert will tell you that you have done so. Because the alert comes up, the browser will jump back to its original size and tell you that it got bigger than 600px again. So you can see, it calls the match function when it matches (so at the time of loading and at the time of resizing to a larger width), and it calls the unmatch function when resizing to a smaller width, because then the media query doesn't match any more. That's how you call a certain function only for mobile or only for desktop based on their screen size.
JS
enquire.register("screen and (min-width:600px)", {
match: function () {
alert("Now the screen width is more than 600px");
},
unmatch: function () {
alert("Now the screen width is less than 600px");
}
});

Related

Standardize image into div

I'm working with Bootstrap and I want to put some photos into my div and I want them to be all at the same size ("standardize").
If they're too big (and they will always be) I want to resize them to fit in my div and crop them if necessary.
For the moment her is what I do :
I've tried to change the style of the image in jQuery in a function:
• If the height is bigger than the width, I switch the style to max-width:100% and height auto.
• Inversement if the width is bigger than the height.
But I'm still new to jQuery and I am probably doing something wrong; can someone light my lantern please?
Here is my jQuery
$(document).ready(function(){
photoResize();
$(window).resize(function(){
photoResize();
});
});
function photoResize(){
image_w = $('img').width();
image_h = $('img').height();
if(image_h > image_w)
{
$('img').css("max-width","100%");
$('img').height("auto");
}
else if(image_w > image_h)
{
$('img').css("max-height","100%");
$('img').width("auto");
}
}
And here is a Fiddle for a better view : https://jsfiddle.net/Baldrani/DTcHh/9801/
Simplicity
I do this quite often in the CMS we use at work for galleries etc. The method I use involves a jQuery library called imgLiquid.js.
This will turn an inline image into a background image on the parent div. It's good because you can achieve your desired effect. It will crop the image (as it technically becomes a background image) and will apply background-size: cover; and background-position: center center; as inline styles.
You can find the plugin here
To initialize the plugin you just need:
$(".myele").imgLiquid();
Overheads
The plugin is very small (roughly around 5.106 KB) so you don't need to worry about adding weight to the page. It really it the most simple method I've come across (bar using thumbnails generated from the sever-side - see note at the bottom).
Cue CSS
I've tested this thoroughly and found it gives excellent results. You may then ask... what happens to my parent divs (as technically the plugin hides the img element - which therefore means the parent element doesn't know what height to make itself).
An easy method to make things work responsively, or not:
.myelement:before{
content: "";
padding-top: 50%;
display: block;
}
This CSS will give your heights back to the wrapping element. So if you wanted certain proportions you could use this math:
h / w * 100 = your percentage for the padding-top.
Working Example
Small note
Technically if I had the control I'd advise just using thumbnails.. I assume you're using some sort of system that could technically just render cut down versions of the images? The reason I use this method — and suggested it — is that I don't have control over the CMS and I'm assuming you just want to manage the code that's being produced as it's not stated.
if you want to make your images the same size then you dont need any javascript or calculations, why not just set it in css?
.someUniqueContainer img{
width:300px;
height:300px; // or what ever height you want
}
I'm guessing that in reality you actually want to crop all your images to a set width/height. if that's the case you'll need a serverside script for that.
where are the images coming from? it would be easyer to just edit them. if they are coming from a user then you would resize/crop on the server on file upload
There were several mistakes in your code.
Please look at this jsfiddle, please see https://jsfiddle.net/DTcHh/9796/
$(document).ready(function () {
photoResize();
$(window).resize(function () {
photoResize();
});
});
function photoResize() {
image_w = $('img').width();
image_h = $('img').height();
if (image_h > image_w) {
$('img').css("max-width", "100%");
$('img').height("auto");
} else if (image_w > image_h) {
$('img').css("max-height", "100%");
$('img').width("auto");
}
}
sth like this?, although this is pure css, not jquery included, might not be suit in your case..
body {
margin-top:20px
}
.col-xs-3 {
margin: 5px 0;
width: 500px;
height:120px
}
.col-xs-3 > div {
width: 100%;
height: 120px;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}
JsFiddle

JS launches before CSS

This is currently happening in chrome, in firefox I haven't had this issue (yet).
Here is a VERY simplified version of my problem.
HTML:
<div class="thumbnail">
Click me!
</div>
CSS:
div {
width: 200px;
height: 300px;
background-color: purple;
}
a {
position: absolute;
}
#media (max-width: 991px) {
div {
height: 200px;
}
}
Javascript:
$(document).ready(function () {
var $parent = $('#clickMe').parent();
function resize() {
$('#clickMe').offset({
top: $parent.offset().top + $parent.height()-$('#clickMe').height()
});
}
$(window).on('resize', resize);
resize();
});
The problem:
So what does this give when I resize (without dragging)? Well javascript launches first and sets the position of the <a></a> , then CSS applies the height change if we are < 992 px.
Logically the button is now visually at the outside of the div and not on the border like I had originally defined it to be.
Temporary solution proposed in this post.
jQuery - how to wait for the 'end' of 'resize' event and only then perform an action?
var doit;
$(window).on('resize', function(){ clearTimeout(doit); doit = setTimeout(resize, 500); });
Temporary solution is not what I'm looking for:
However, in my situation I don't really need to only call 'resize' when the resizing event is actually done. I just want my javascript to run after the css is finished loading/ or finished with it's changes. And it just feels super slow using that function to 'randomely' run the JS when the css might be finished.
The question:
Is there a solution to this? Anyone know of a technique in js to wait till css is completely done applying the modifications during a resize?
Additional Information:
Testing this in jsfiddle will most likely not give you the same outcome as I. My css file has many lines, and I'am using Twitter Bootstrap. These two take up a lot of ressources, slowing down the css application (I think, tell me if I'm wrong).
Miljan Puzović - proposed a solution by loading css files via js, and then apply js changes when the js event on css ends.
I think that these simple three steps will achieve the intended behavior (please read it carefully: I also suggest to read more about the mentioned attributes to deeply understand how it works):
Responsive and fluid layout issues should always be primarily (if not scrictly) resolved with CSS.
So, remove all of your JavaScript code.
You have positioned the inner a#clickMe element absolutely.
This means that it will be positioned within its closest relatively positioned element. By the style provided, it will be positioned within the body element, since there is no position: relative; in any other element (the default position value is static). By the script provided, it seems that it should be positioned within its direct parent container. To do so, add position: relative; to the div.thumbnail element.
By the script you provided, it seems that you need to place the a#clickMe at the bottom of div.thumbnail.
Now that we are sure that the styles added to a#clickMe is relative to div.thumbnail, just add bottom: 0px; to the a#clickMe element and it will be positioned accordingly, independently of the height that its parent has. Note that this will automatically rearrange when the window is resized (with no script needed).
The final code will be like this (see fiddle here):
JS:
/* No script needed. */
CSS:
div {
width: 200px;
height: 300px;
background-color: purple;
position: relative; //added
}
a {
position: absolute;
bottom: 0px; //added
}
#media (max-width: 991px) {
div {
height: 200px;
}
}
If you still insist on media query change detection, see these links:
http://css-tricks.com/media-query-change-detection-in-javascript-through-css-animations/
http://css-tricks.com/enquire-js-media-query-callbacks-in-javascript/
http://tylergaw.com/articles/reacting-to-media-queries-in-javascript
http://davidwalsh.name/device-state-detection-css-media-queries-javascript
Twitter Bootstrap - how to detect when media queries starts
Bootstrap: Responsitive design - execute JS when window is resized from 980px to 979px
I like your temporary solution (I did that for a similar problem before, I don't think half a second is too long for a user to wait but perhaps it is for your needs...).
Here's an alternative that you most likely have thought of but I don't see it mentioned so here it is. Why not do it all through javascript and remove your #media (max-width.... from your css?
function resize() {
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
if(width<992){
$("div").each(function(e,obj){$(obj).height(200);});
}
$('#clickMe').offset({
top: $parent.offset().top + $parent.height()-$('#clickMe').height()
});
}
In the html page, put the link to css file in head section; next, put the link to js file just before the /body tag and see what happens. In this way css will load always before js.
Hope this help you.
Did you try to bind the resize handler not to the window but to the object you want to listen to the resize ?
Instead of
$(window).on('resize', resize);
You can try
$("#clickMe").on('resize', resize);
Or maybe
$("#clickMe").parent().on('resize', resize);
var didResize = false;
$(window).resize(function() {
didResize = true;
});
setInterval(function() {
if (didResize) {
didResize = false;
console.log('resize');
}
}, 250);
I agree with falsarella on that you should try to use only CSS to do what you are trying to do.
Anyway, if you want to do something with JS after the CSS is applied, I think you can use requestAnimationFrame, but I couldn't test it myself because I wasn't able to reproduce the behavior you explain.
From the MDN doc:
The window.requestAnimationFrame() method tells the browser that you
wish to perform an animation and requests that the browser call a
specified function to update an animation before the next repaint. The
method takes as an argument a callback to be invoked before the
repaint.
I would try something like this:
var $parent = $('#clickMe').parent();
function resize(){
$('#clickMe').offset({
top: $parent.offset().top + $parent.height()-$('#clickMe').height()
});
}
window.onresize = function(e){
window.requestAnimationFrame(resize);
}
window.requestAnimationFrame(resize);
Anyone know of a technique to wait till css is completely done loading?
what about $(window).load(function() { /* ... */ } ?
(it executes the function only when the page is fully loaded, so after css loaded)

Get AngularJS to play nice with other javascript

I have started using AngularJS with some code that was already written and need to get it to play nice together.
So I have
<html ng-app="MainPage">
<head>
...Some JS includes
</head>
<body>
<div id="divDropDownMenu" class="DropDownMenu">
....AngularJS stuff in here
</div>
</body>
I'm using this code to append a button at the end of "divDropDownMenu" and when the button is clicked slide the up and down to reveal the menu items.
var divPanel = $("<div class='slide-panel'>");
var divContent = $("<div class='content'>");
(function ($, $scope) {
$.fn.slideBox = function(params){
var content = $(this).html();
var defaults = {
width: "100%",
height: "500px",
position: "top" // Possible values : "top", "bottom"
}
// extending the function
if(params) $.extend(defaults, params);
$(divContent).html(content);
$(divPanel).addClass(defaults.position);
$(divPanel).css("width", defaults.width);
// centering the slide panel
$(divPanel).css("left", (100 - parseInt(defaults.width))/2 + "%");
// if position is top we're adding
if(defaults.position == "top")
$(divPanel).append($(divContent));
// adding buttons
$(divPanel).append("<div class='slide-button'>Open Menu</div>");
$(divPanel).append("<div style='display: none' id='close-button' class='slide-button'>Close Menu</div>");
if(defaults.position == "bottom")
$(divPanel).append($(divContent));
//$(this).replaceWith($(divPanel));
// Buttons action
$(".slide-button").click(function(){
if($(this).attr("id") == "close-button")
$(divContent).animate({height: "0px"}, 1000);
else
$(divContent).animate({height: defaults.height}, 1000);
$(".slide-button").toggle();
});
};
})(jQuery);
function SlidePanelExpandCollapse(ExpandCollapse)
{
if (ExpandCollapse == "Expand") {
$(divContent).animate({ height: defaults.height }, 1000);
}
else {
$(divContent).animate({ height: "0px" }, 1000);
}
$(".slide-button").toggle();
}
The problem is that any angular inside the targeted div does not fire when using the above code.
this is the CSS that goes with the above JS menu slider
/* #override
http://samuelgarneau.com/slidebox.css
http://samuelgarneau.com/lab/validator/slidebox.css
http://samuelgarneau.com/lab/slidebox.css
http://samuelgarneau.com/lab/slidebox/style/slidebox.css
*/
body {
margin: 0;
padding: 75px 0 0;
}
.slide-panel {
z-index: 9999;
width: 5px;
position:absolute;
}
.bottom {
bottom: 0;
}
.right {
}
.left {
position: absolute;
left: 0;
}
.top {
top: 0;
}
.content {
margin-left: auto;
margin-right: auto;
z-index: 10;
overflow: hidden;
text-align: left;
background-color: #343434;
height: 0;
width: 100%;
color: #fff;
}
.slide-button {
background: none repeat scroll 0 0 gray;
margin-left: auto;
margin-right: auto;
position:relative;
width: 150px;
z-index: 20;
cursor: pointer;
height: 30px;
padding-top: 10px;
text-align: center;
}
.slide-button:hover {
color: #ffffff;
}
I don't see any actual use of AngularJS in your example at all. The only thing which reminded me of AngularJS was the mention of $scope in your function definition. Now while AngularJS appears to work magically in some areas this still won't do anything.
Also it might appear tempting to keep existing code and just add some AngularJS parts. However seeing your example I would recommend that you rewrite this functionality using the means of AngularJS. Showing and Hiding stuff can be easily done with ng:hide or ng:show. The animation stuff you do can be done with ng:animate. And if you need to dynamically show data, put it into a model (in your scope) and use that with functions like ng:repeat.
It appears that what you are doing in your example would boil down to only a couple of lines using the AngularJS functionality, so the result would be better and easier to read and maintain. Do yourself a favor and get familiar with what AngularJS can provide you with and stop bothering with direct DOM manipulation. It is a bad pattern. DOM manipulation is pesky, complicated and prone to break. It is also usually an unmaintable mess. And the best: If you are using AngularJS anyway, it is complete superflous because everything can be achieved much easier by having a model triggering conditional logic in your HTML.
Some impressive fact from the talk of the AngularJS creator at Google I/O 2013: He used AngularJS in its beginning to rewrite a internal project of Google. The result was that 14000 lines of code were reduced to 1500.
I recognize that this does not really count as an answer to your problem but I really believe that you would be better off stopping this approach right here and now and instead of wasting time to get this working rewrite it in AngularJS. This seriously should not take longer than half an hour even if you have to read up all the details still.
Edit/Addendum: The talk I mentioned is "Google I/O 2013 - Design Decisions in AngularJS" at http://www.youtube.com/watch?v=HCR7i5F5L8c I highly recommend watching this video even to people who have already experience with AngularJS. It gives good insight to the AngularJS way and its points come handy when trying to convince someone else in trying AngularJS :)
Edit/Addendum2: As Sprottenwels helpfully mentioned above, there is another question here on stackoverflow which gives a much more thorough explanation of what I boiled down above, so please give it a read: "Thinking in AngularJS" if I have a jQuery background?
Edit/Addendum3: As again Sprottenwels helpfully mentioned: The videos at http://www.egghead.io/lessons are a great resource. I personally found them sometime a little hard to understand (you might need to stop the video and read up in the documentation of AngularJS which thankfully is nowadays much better than it used to be).
Oh and on a personal note: While I did web development since about 1997, I was never a friend of doing application like stuff in JavaScript because all those frameworks are so complicated with lots of boilerplate and you are doing stuff which feels like a waste of time. AngularJS really did wonders to my motivation doing such stuff because it finally is totally logical and its magically like inner workings totally freed me from doing stuff I hated like synchronisation of data and view.
I am totally thankful to the AngularJS people and I absolutely believe that this is the only real future of doing web application programming. Right now AngularJS can be a problem performance-wise because of doing "bad" stuff like dirty-checking but this is going to change with new browser features like Object.observe. So I really think that choosing to use AngularJS to its full extent is a wise and future-safe move.

javascript web print. print a logo in the header of every page

My trouble is I don't know how many pages it has when printing.
I have used the following CSS:
#media print {
.barcode{
position: fixed;
}
}
So that the image appears in each page when printing. but on the second page or third page the image will overlap the content of the page as the screenshot.
You can try something like this:
HTML
<div class='barcode'><!-- Barcode content --></div>
CSS
.barcode { display:none; }
#media print {
.barcode { display: block; position: fixed; top: -20px; height: 50px; }
}
The div needs to be positioned fixed in order to appear on every printed page. You can try adjusting the top property to position and move it above the content.
After reconsidering this, a much better solution would be to generate a PDF version of the page for printing. Then you'll have much more control. There are numerous PDF libraries out there for all server languages.
It's not possible to control this directly. What you can try to do is regularly force page breaks and apply a height to that spacer div. For example:
#media all
{
div.page-break { display:none; }
}
#media print
{
div.page-break { display:block; height: 100px; page-break-before:always; }
}
This will only work, though, if you place enough <div class="page-break"></div>s in your page such that one appears before every natural page break would occur.
Reference: http://davidwalsh.name/css-page-breaks
I don't speak english, sorry. I solved similar issue following instruction on this page : http://thewebthought.blogspot.com/2011/10/html-css-header-and-footer-elements-for.html

Making a DOS-style window in ASP.net

I'm trying emulate the MS-DOS command prompt on my website. I don't need to accept keystrokes, but I'd like to append data at the bottom and optionally scroll upwards.
At first I looked at the asp:TextBox and asp:Label, but the flicker of using postbacks seemed to be too much. I'm now considering DIV tags and Javascript where I simply update the InnerHTML property, but there too I get flicker, and have issues with scrolling.
What solution would you recommend in this situation? Essentially I'm trying to count to infinity, with a 1 sec delay, only need the most current 300 or so entries, with the most current entry at the bottom of the screen.
Is this even possible with JS/CSS?
Do you wish to make it a little more stylous ? :)
see this page...
http://www.klaus.dk/Some_unknown_page
or this one
http://www.harryovers.com/404.html?aspxerrorpath=/Account/LoginPartial
here is the javascript source code.
http://code.google.com/p/c64-404-page/
With a little change, you can append your text on this code :)
I just built something very similar using jQuery. You can use the append method to add content to the bottom of your DIV. You can then set the scrollTop attribute to keep things scrolled to the bottom as follows:
$("#someDiv").attr({ scrollTop: $("#someDiv").attr("scrollHeight") });
I think "DOS-style window" is a bit misleading considering all you want to do is append text to a div and make sure it stays scrolled to the bottom.
function addLine(text) {
var box = document.getElementById('DOSBox') //teehee
var line = document.createElement('p');
line.innerHTML = text;
box.appendChild(line);
box.scrollTop = box.scrollHeight;
}
And style it as such
#DOSBox {
overflow: auto;
display: block;
height: 400px; width: 500px; /* or whatever */
/* and if you want it to look DOS-like */
background: #000;
color: rgb(192, 192, 192);
font-family: fixedsys;
}
#DOSBox p {
margin: 0;
}

Categories