'Mobile first' image loading for Wordpress sider - css

All the image slider plugins I have used so far for Wordpress sites have had no way, as far as I could tell, to swap out different sized images at various screen sizes to enable an 'mobile first' experience.
For example: http://www.akqa.com/
They have changed which image is displayed depending on certain breakpoints and it allows control over which part of the image is displayed.
If there is no plugin to automate this, could it at least be achieved through CSS alone?
Thank you

You can do this by HTML picture tag or Jquery .data()
Jquery Example
orignalImg = $(".test").attr("src"); // get orignal image
mobileImg = $(".test").data("mobile"); // get mobile image
brakpoint = 768; //what ever your brakpoint
//do magic
function changeImg() {
$(".test").each(function() {
if ($(window).width() <= brakpoint) {
$(this).attr("src", mobileImg);
}else {
$(this).attr("src", orignalImg);
}
});
}
// call magic
changeImg();
//change image if viewport change
$(window).on('resize', function() {
changeImg()
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Resize your window </h1>
<img class="test" src="http://placehold.it/600x300" data-mobile="http://placehold.it/300x600">
HTML Example
<picture>
<source srcset="http://placehold.it/600x300" media="(min-width:768px)">
<img src="http://placehold.it/300x600" alt="img">
</picture>
In your example link they are also using this <picture> tag. This is a simple solution but might be you will face browser compatibility issue

Related

Hide Play Button Overlay on <video> in iOS 14

I have a short, ~2-second video that plays on a loop in the background of a website I'm making, which, when it appears through transparent portions of divs, gives the effect of a metallic shimmer. It looks great. The problem is, when an iOS device is in low power mode, the video not only doesn't play (which is acceptable, I get it), it shows a big honkin' play button that shows through those same transparent portions of divs. I need to get rid of that, but every solution I've found seems to not work in iOS 14.
Here's the video tag:
<video id="videoElement" src="copper.mp4" autoplay loop playsinline muted webkit-playsinline></video>
…and the CSS:
video#videoElement::-webkit-media-controls,
video#videoElement::-webkit-media-controls-start-playback-button,
video#videoElement::-webkit-media-controls-play-button,
video#videoElement::-webkit-media-controls-panel,
video#videoElement::-webkit-media-controls-container,
video#videoElement::-webkit-media-controls-overlay-play-button,
video#videoElement::-webkit-media-controls-enclosure {
display: none !important;
-webkit-appearance: none;
opacity: 0 !important;
}
You can do this with JQuery. Include it with this:
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>
The following code will play the video as soon as the user interacts with their device in any way. This also acts as a workaround for regular safari autoplay issues.
<script type="text/javascript">
$('body').on('click touchstart', function () {
const videoElement = document.getElementById('videoElement');
if (!videoElement.playing) {
videoElement.play();
}
});
</script>
You can't trigger video playback without the user interacting with device (this is probably a good thing).
If you'd like to instead completely disable playback when low power mode is enabled (and some of us will thank you greatly), you can do the following:
<script type="text/javascript">
var promise = $('#videoElement').play();
if (promise !== undefined) {
promise.then(_ => {
// Autoplay was successful
}).catch(error => {
$('#videoElement').remove()
});
}
</script>
I'll dig some more to see if there's a way to do this with pure CSS, but I doubt it'll be anywhere near as "stable".

Center spinner in viewport on bootstrap overlay

I'm using the bootstrap-vue overlay on a page that has long content scrolled via the browser window.
<b-overlay :show="loading">
The overlay correctly covers all of the content, even the part below the viewport, but the overlay's built-in spinner is centered on the content rather than the viewport, so the spinner ends up near or below the bottom of the viewport when the content is long enough.
I've tried custom content via a slot, like this...
<b-overlay :show="loading">
<template v-slot:overlay>
<div style="???" class="text-center">
<p style="???">Make me a spinner and center me on the viewport</p>
<b-button
</div>
</template>
...with dozens of ideas for style="???", including position:absolute with different tops, including top=50vh, including !important strewn around, etc., but the content doesn't budge.
// Note that this snippet doesn't run, because I don't see a way to get
// bootstrap-vue via CDN
var app = new Vue({
el: '#app',
data: function() {
return {
message: 'Hello Vue!',
messages: []
}
},
mounted() {
for (let i=0; i<50; i++)
this.messages.push(i)
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<b-overlay :show="true">
{{ message }}
<!-- long content below extends the overlay size -->
<!-- this moves the spinner down and off the viewport -->
<ul>
<li v-for="m in messages" :key="m">{{m}}</li>
</ul>
</b-overlay>
</div>
I think key to solving this is finding the CSS selector that allows me to change the spinner's position to "fixed" as opposed to "absolute" which seems to be what bootstrap generates.
To get spinner on center of screen you need to make it as direct child of body.
If it is nested it will have restrict area inside immediate parents area.
Try to add that separately or once your DOM ready detach overlay and append to body tag.
I ran into the same issue. Adding this line of CSS on the component resolved it for me:
<style>
.position-absolute {
position: fixed !important;
}
</style>
Note: make sure to not include the scoped keyword in your <style> tag, as this will not work for Bootstrap classes.

angularjs delay route change upon click as long new background image does not load

My web app shows body background for a second then it loads the dynamic background when i route from one page to another. I am trying to remove that white flash by adding a splash screen using AngularJS. I looked at some tutorials but were not able to find exact solution.
how do i avoid showing the white body background before my div background loads?
any suggestions?
HTML
<body class="hold-transition skin-blue sidebar-mini sidebar-collapse">
<div class="wrapper" ng-style="{'background': backgroundImg}" >
<div class="content-wrapper">
<section class="content">
<div ng-view></div>
</section>
</div>
</body>
my route
$routeProvider.when('/about',{
templateUrl:'partials/about.php',
controller: 'pageController'
});
My controller
app.controller("pageController",function($scope, $rootScope){
$scope.title = "About Us";
$rootScope.backgroundImg="url('http://abounde.com/uploads/images/abt-min.jpg')"; //abt bg
$scope.$on('$viewContentLoaded', function() {
console.log("about page loaded");
});
});
From what I understand, the pb is that when you route to another page then you launch a new request to download your background with your url(...). Because this request can take time then you have your white screen.
So a solution could be to "preload" all background images when you open your app. So before displaying anything on your app you can display a "loading..." div. In background download all your backgrounds.
Once this is done, when changing route then simply change the css class of your wrapper div to the css class containing the correct background image.
On this particular page, you could have a div that wraps the entire document.
Give this div a class with css ie .document-wrapper-invisible
in your css give .display-none class a display property of none
.dislay-none {
display: none;
}
When your view content loaded function runs, remove this class. You can simply set a variable to be true and use ng-class to conditionally remove the class. ie
<div ng-class="{display-none: !documentLoaded}">
// your page content
</div>
in your controller
$rootScope.$on('$viewContentLoaded', function() {
console.log("about page loaded");
$scope.documentLoaded = true;
});
Something along these lines should work (I've only ever used rootScope for the viewContentLoaded event, if $scope works on it's own then great)

Prevent Bootstrap from preloading all the hidden-* images

I'm running Twitter Bootstrap 3.2.
My page has a banner image for every breakpoint. That means code like this:
<img class="visible-xs img-responsive" src="headline-768px.jpg"> (128kb)
<img class="visible-sm img-responsive" src="headline-992px.jpg"> (144kb)
<img class="visible-md img-responsive" src="headline-1200px.jpg"> (264kb)
<img class="visible-lg img-responsive" src="headline-2000px.jpg"> (380kb)
The main purpose of having 4 different images is so that mobile devices don't need to download the larger versions. But Bootstrap preloads all the versions regardless of screen size, even if they're hidden at the current breakpoint. This amounts to hundreds of unnecessary kb for every viewer.
Is there a way around this?
Demo of the Problem:
Not all browsers react the same, but typically browser's will load content from a src attribute, regardless of whether some other CSS rule renders that element as invisible.
Here's a baseline example:
<img class="visible-xs img-responsive" src="http://placehold.it/768x150" />
<img class="visible-sm img-responsive" src="http://placehold.it/992x150" />
<img class="visible-md img-responsive" src="http://placehold.it/1200x150"/>
<img class="visible-lg img-responsive" src="http://placehold.it/2000x150"/>
Demo in jsFiddle
Whenever I refresh the page, the browser loads all images, even ones that are initially invisible:
Background Image + Media Queries
This tutorial on Simple Responsive Images With CSS Background Images goes into more depth, but the basic solution works like this:
Create a simple div:
<div class="responsiveBackgroundImage" id="myImage" ></div>
And then sub in the correct background image depending on the screen size:
We'll probably want all the background images to share a couple basic properties like this:
.responsiveBackgroundImage {
width:100%;
background-size: 100%;
background-position: 50% 0%;
background-repeat: no-repeat;
}
Then replace the background-image property for this particular element at each resolution:
#myImage {background-image: url(http://placehold.it/768x150); }
#media (min-width: 768px) { #myImage { background-image: url(http://placehold.it/992x150); }}
#media (min-width: 992px) { #myImage { background-image: url(http://placehold.it/1200x150);}}
#media (min-width: 1200px) { #myImage { background-image: url(http://placehold.it/2000x150);}}
Demo in jsFiddle
Replacing Images with Javascript
Due to limitations with using background images, you might decide to use a real img element and then just dynamically load the images. Rather than loading the element itself, you can do something similar to what angular does with ng-src when evaluating an expression that resolves to a url. When the browser loads each element, it wouldn't be able to find the file location of src="{{personImageUrl}}". Instead, Angular saves the intended url as a data attribute and then loads when appropriate.
First, take each of your images and prefix the src attribute with data-. Now the browser won't automatically start implementing anything, but we still have the information to work with.
<img class="visible-xs img-responsive" data-src="http://placehold.it/768x150"/>
Then query for all the dynamic images we'll eventually want to load.
$dynamicImages = $("[data-src]");
Next, we're going to want to capture window resize events, and on the very first page load, we'll trigger one just so we can make use of the same code. Use a function like this:
$(window).resize(function() {
// Code Goes Here
}).resize();
Then check if each dynamic image is visible. If so, load the image from the data attribute and remove it from the array so we don't have to keep checking and loading it.
$dynamicImages.each(function(index) {
if ($(this).css('display') !== 'none') {
this.src = $(this).data('src');
$dynamicImages.splice(index, 1)
}
});
Demo in jsFiddle
it is not bootstrap, but the browser. You should use background images (instead of <img> tags) together with media queries.
A proper browser will load only the css background image matching the media query, but it makes sense for it to load all images in the markup regardless of their css styling
(Necessary pain until <picture> will be widely supported)
I did it with jQuery in the end.
HTML:
<div id="billboard">
</div>
Javascript:
$(document).ready(function(){
var viewportWidth = $(window).width();
var adaptiveBillboard = function($showTheRightSizeBilboard){
if(viewportWidth<641){
$('#billboard a').html('<img class="img-responsive" src="http//i.imgur.com/ISYNyCw.png">');
}else if(viewportWidth<721){
$('#billboard a').html('<img class="img-responsive" src="http//i.imgur.com/OQeEwOq.png">');
}else if(viewportWidth<769){
$('#billboard a').html('<img class="img-responsive" src="http//i.imgur.com/3WqOdgo.png">');
}else if(viewportWidth<993){
$('#billboard a').html('<img class="img-responsive" src="http//i.imgur.com/KpNKYLq.png">');
}else if(viewportWidth<1201){
$('#billboard a').html('<img class="img-responsive" src="http//i.imgur.com/F00kkbv.png">');
}else{
$('#billboard a').html('<img class="img-responsive" src="http//i.imgur.com/FK5ZMoo.png">');
};
};
//try things once on pageload
$(adaptiveBillboard);
//try things again on every viewport resize
$(window).resize(function(){
viewportWidth = $(window).width();
setTimeout(adaptiveBillboard,100);
});
});
I have used (in combination with bootstrap hidden-xs):
$dynamicLoadImages = $("img.hidden-xs[data-src]");
$(window).resize(function(index) {
for (var i = 0; i < $dynamicLoadImages.length; i++) {
el = $dynamicLoadImages[i];
if ($(el).css('display') !== 'none') {
el.src = $(el).data('src');
$dynamicLoadImages.splice(i, 1);
i--;
}
};
}).resize();
The current top solution works only for every odd element because of the splice method modifying the underlying object and then skipping the next element.

Images not displaying when Print Preview (Or Print) in IE/Chrome/Firefox

I'm Web Developer and almost never work with design but have been given this bug which I'm struggling to rectify.
Some images appear correctly when I print/display the print preview page, however others don't. The key difference that I can see is that the images that don't appear are span tags with the image applied in css whilst the working images use the img tag.
Here are examples of the html:
Span with "icon" birth does not display:
<li class="media">
<div class="img">
<div class="h2 mtm">1889</div>
<span class="timeline-icon icon-birth"></span>
</div>
<div class="bd">
<h3 class="profile-subtitle mts">Born in ?</h3>
<p class="deemphasis mbn">
Search for Birth Record
</p>
</div>
</li>
Image.gif does display:
<li class="media">
<div class="img">
<div class="h6">
<strong>Spouse</strong></div>
<img src="image.gif" alt="" class="person-thumb dropshadow" />
</div>
<div class="bd">
<p class="mbn">Husband</p>
<h3 class="profile-subtitle">
Thomas <strong>Name</strong>
</h3>
<p class="mbn">?-?</p>
</div>
</li>
In some browsers it looks ok in the preview but does not print, in others it doesn't and still does not print.
Thankyou in advance!
I had the same problem over two months ago. I had a button that redirected users to a printer-friendly page and then I triggered print dialog using Javascript.
The problem was that browsers did not wait till images specified in CSS background were downloaded.
I put timeout before triggering the print dialog to give browser time to download images. This approach is not reliable since nobody has constant download speed and it would open the print dialog before the images are downloaded to users with very slow Internet connection.
In the end, I used HTML img tags to embed images on my page and jQuery to trigger the print dialog when the last image is downloaded.
You need to put delay before print. There is a native bug in chrome. Code would as under :-
function PrintDiv(data) {
var mywindow = window.open();
var is_chrome = Boolean(mywindow.chrome);
mywindow.document.write(data);
if (is_chrome) {
setTimeout(function() { // wait until all resources loaded
mywindow.document.close(); // necessary for IE >= 10
mywindow.focus(); // necessary for IE >= 10
mywindow.print(); // change window to winPrint
mywindow.close(); // change window to winPrint
}, 250);
} else {
mywindow.document.close(); // necessary for IE >= 10
mywindow.focus(); // necessary for IE >= 10
mywindow.print();
mywindow.close();
}
return true;
}
Just add the below styles to make it work img{max-width:100%;height:auto;}
Its the width of the image being set to 0 in the print which is causing the issue.
make a print stylesheet, set your span to display:block

Resources