I'm hoping to use PhotoSwipe to display all the images in each article on my responsive site, like the gallery you get when you click or tap on an in-content image in http://dailymail.co.uk. The main use is to give users a big view of pics and allow them to zoom in to them on mobile devices without leaving the article.
PhotoSwipe works very well for this purpose. My JS combs through the article content and builds the PhotoSwipe array from the images it finds. But there's one problem: some of the images in my articles are small. This isn't too bad on a mobile, but on desktop I'm liable to end up with a small image in the middle of a big black gallery area. The Daily Mail get around this problem by always stretching their images up to fit the gallery area - slightly ugly with some pics, but it gives a big view.
Is there any way I can selectively stretch small images in my PhotoSwipe gallery to fill more of the available area? An older version of PhotoSwipe used to have a imageScaleMethod option that would allow you to fit images to the screen size: is there anything similar I can do with the latest version, v4.0.7?
Here's a CodePen which should illustrate what I'm talking about - the third image is the sort of image I'd like to stretch up a bit. My slides in this example are:
var items = [
{
src: 'http://lorempixel.com/1000/750/cats/',
w: 1000,
h: 750,
title: 'Fairly big cat'
},
{
src: 'http://lorempixel.com/1200/900/cats/',
w: 1200,
h: 900,
title: 'Another quite big cat'
},
{
src: 'http://lorempixel.com/200/320/cats/',
w: 200,
h: 320,
title: 'Small cat'
}
];
At first I thought I could solve this by adding a beforeChange listener which zooms each image in to fit the display area as it comes in. Conveniently, each item in PhotoSwipe has a property fitRatio which represents the zoom ratio required to fit the display area.
On line 34 of my CodePen, just before the line that goes gallery.init(); I added:
gallery.listen('beforeChange', function () {
gallery.zoomTo(gallery.currItem.fitRatio, {x: gallery.viewportSize.x / 2, y: gallery.viewportSize.y / 2}, 1);
});
which zoomed the current pic to the right ratio to fit the gallery, centred on the slide's x and y centre, and over a duration of 1 microsecond. (See the PhotoSwipe API documentation for details about the zoomTo method.)
But zooming in deactivates the "click swipe" action on desktop, and I wanted to keep it.
So instead I'm measuring the browser window and setting the image width and height to match. You have to take account of whether the image is landscape vs portrait, and you need to update your dimensions if the user resizes the browser window.
var measureWindow = function () {
windowW = $window.width();
windowH = $window.height();
};
measureWindow();
// If image is landscape or square, set width to window width and height to width * ratio
// If image is portrait, set height to window height and width to height / ratio
var getImageDimensions = function (w, h) {
var ratio = h / w;
if (w >= h) {
return {
width : windowW,
height: windowW * ratio
}
} else {
return {
width : windowH / ratio,
height: windowH
}
}
};
Then as I add each of the images to my array I do
var dimensions = getImageDimensions(width, height),
o = {
el : value,
src: src,
w : dimensions.width,
h : dimensions.height
};
where o is the object representing the image.
I also add a listener to my gallery to call measureWindow again if the user resizes the window. This updates windowW and windowH.
var debouncedMeasure = _.debounce(measureWindow, 250);
gallery.listen('beforeResize', function () {
debouncedMeasure();
});
Strictly speaking I should update the dimensions in my images array when this happans, so new images are correctly sized to the new window dimensions.
Here's the solution I ended up with - you need to view the full preview to see how it works.
EDIT
To get the best results from PhotoSwipe, I've found I have to hide the content in the rest of the page whenever it's active. When I open it I do
html.addClass('photoswipe-active');
gallery.listen('close', function () {
html.removeClass('photoswipe-active');
});
and set visibility:hidden on the other content when that class is present. If you have anything in the page that causes a repaint (like an animated gif) it can cause a stutter in PhotoSwipe's swipe and pinch to zoom gestures. Hiding the content keeps it smooth.
I also had performance problems when I tried to measure the PhotoSwipe element on resize - it seems much better to measure the window instead.
I was using the wordpress plugin and added the following css.
(I then set the thumbnail size in wordpress to 0 0.)
.photoswipe_gallery_holder {
width: 101%;
margin-left: -5px;
}
.photoswipe_gallery {
width: 100%!important;
margin-top: 20px!important;
margin-bottom: 20px!important;
margin-right: 0px!important;
margin-left: 0px!important;
padding-bottom:0px!important;
}
.photoswipe_gallery figure {
width: 100%!important;
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
padding: 5px!important;
}
.photoswipe_gallery figure img {
width: 100%!important;
height: auto!important;
padding: 0px!important;
}
.photoswipe_gallery figure a {
width: 100%!important;
height: auto!important;
}
#media screen and (min-width: 480px) {
.photoswipe_gallery figure {
width: 50%!important;
}
}
#media screen and (min-width: 750px) {
.photoswipe_gallery figure {
width: 25%!important;
}
}
The "holder" div is so we can shift things abit to line up. If you use this, you need to set overflow: hidden; on the parent div. My parent div was 968px wide at the widest on a responsive site.
If you look at the source code you can see it is/was a planned feature at some point, as it has parts that say:
// not fully implemented yet
scaleMode: 'fit' // TODO
This is indeed not much of a help, but I'm just saying this as an interesting detail.
My solution to the problem was this: simply set the data-size attribute to a size, that is bigger than most common screen sizes. As I'm generating the markup from PHP, I simply put something like this:
data-size="<?php echo intval($img_x * 1.5); ?>x<?php echo intval($img_y * 1.5); ?>"
The actual number required may vary in your case, but I had all my images already set to a fixed size and the 1.5 multipliers were enough to make them fill most screens.
It is not a "correct" solution, however, it is simple, quick and lightweight for the client (no additional javascript magic is needed). It may be a benefit for simple projects compared to the elaborate JavaScript heavy solution suggested above.
In fact, I'm using MobileDetect so I'm only increasing the image size for desktops, as my original images are suitable for mobiles (and tablets).
data-size="<?php echo intval($img_x * ($mobile_detect->isMobile() ? 1 : 1.5)); ?>x<?php echo intval($img_y * ($mobile_detect->isMobile() ? 1 : 1.5)); ?>"
You need to plan the sizings according to your own needs and you may need to use different multipliers for each image, but my point is that the size manipulation can be done easily in the gallery markup, instead of trying to override the values from JavaScript or to force zooming PhotoSwipe after certain events (which I've tried and worked more-or-less fine for switching the images, but it caused glitches when opening PhotoSwipe for example).
Related
To illustrate my question, here is a not-real example:
<img src='myimage-low.png' style='width: 150px;'>
<img src='myimage-high.png' style='width: 150px;'>
myimage-low.png is 150px x 100px
myimage-high.png is 1500px x 1000px
When I am zoomed all the way out on the web page, both images look the same. When I zoom in, the high definition image looks much better.
If I use javascript to get the image width with $(elem).width();, it says (as I would expect) 150px for both, regardless of the zoom.
Is there a way in javascript to get the actual screen size of the element as presented to the user? In my above example, they might both say "100px" when I'm fully zoomed out, and "1000px" when I'm fully zoomed in.
Note - I need to be able to need this for both <img> elements as well as any element that might have a css background-image.
For context, this is to determine which resolution of an image to load. There's no point in loading the 1500px if the user is on a low resolution and it will just be resized in the browser to 300px - they might as well have the 500px version which is faster to download.
Say hello to window.devicePixelRatio:
var el = document.querySelector('img');
function getElemSize(el) {
var rect = el.getBoundingClientRect();
return {
width: Math.round(rect.width * window.devicePixelRatio),
height: Math.round(rect.height * window.devicePixelRatio)
};
}
function updateSize() {
var size = getElemSize(el);
document.querySelector('p').innerHTML = JSON.stringify(size);
}
el.addEventListener('load', updateSize);
addEventListener('resize', updateSize);
<img src="https://howitworks.wpengine.com/wp-content/uploads/2015/09/214887-puppies-cute-puppy.jpg" style="width: 150px">
<p></p>
You can use the visualViewport API to multiply the width by the scale if you're looking for pinch zoom:
const { scale } = window.visualViewport;
const width = $(elem).width() * scale;
I tried adding a snippet for an example, but according to the spec the window.visualViewport.scale inside of an iframe is always 1. As long as your content is not in an iframe, this method will work for giving you the scale of the pinch zoom (tested in my browser console)
I'm trying to wrap my brain around viewports / scales. I have a site I have to program, and the design I've been given is responsive, but it really doesn't work if the device's width is below 420px.
At anything below 420px, I'd love it if the browser would render the site as if it were 420px wide, just zoom everything out, but I can't figure out how to do this.
I've seen how you can dynamically change the meta viewport tag, but when I do this, it doesn't seem to have any affect, and I'm not sure that's the best way to approach what I'm trying to achieve.
At any rate, this is what I tried:
var minBP = 420;
//ww = window width
if (self.ww < minBP && lastScreenWidth > minBP){ //site is smaller than minimum allowed width, modify viewport
var viewportString = "width=" + minBP + ", initial-scale=1.0";
$('#blackrock-viewport').attr('content',viewportString);
}
Anyone know how to render a scaled-out 420 viewport width when the browser drops below these dimensions?
well you can do that in css by using Media Queries it allows you to manipulate evrything in diffrent screens
for exemple if you want to change the width of div in 420px screen you can do this :
#media (min-width:420px) {
div{
width:50px;
}
}
You can just use media queries to target specific elements on specific screen sizes.
For your situation, you just have to limit your wrappers width to your preferred size.
Supposing that you have a div that wraps all your page, let's say .wrapper.
#media screen and (max-width:420px) {
.wrapper{
width:420px;
}
}
Of course, you can do this also without media queries by just setting the min-width property of your wrapper.
.wrapper{
min-width:420px;
}
But I suppose that with media queries you are more flexible.
I'm trying to change the size of divs depending of screen size.
If the phone is laying it changes the sizes of divs.
Example:
block is default: 330px width and 250px high on a 768x1280 screen resolution.
The factor is:
width: 330px; factor x 2,18
height: 250px; factor x 5,12
When i change my phone to laying the sizes should be:
width: 587px
height: 150px
which doesnt work in the first place, can someone tell my why not?
js:
var devicewidth = $( window ).width();
var deviceheight = $( window ).height();
var mbwsize = devicewidth / 2.18;
var mbhsize = deviceheight / 5.12;
var mbisize = mbhsize / 1.25;
$('#mainmenublok').css('width', mbwsize+'px');
$('#mainmenublok').css('height', mbhsize+'px');
$('#mainmenublok').css('background-size', mbisize+'px'+mbisize+'px');
dont get errors, it just keeps the content in the middle as 720px width (768 - offset)
I changed the main div already here:
$('#maintable').css('width', devicewidth+'px');
Will try to change window to document but can someone look at this?
With document it doesnt change either.
The calculation is correct if you look at the picture at the debug.
I also tried it in a function but that did not work.
Added a picture to explain what happens
explain:
debug:
Based on the HTML provided by the author in the comments
<div onclick="bb.pushScreen('timeline.html', 'timeline');"class="mainmenublok" id="blocktimeline" style="background-image:url(ico/timeline.png); background-size:200px 200px; background-repeat: no-repeat; background-position:center;">
<img id="pictimeline" src="ico/bbaction.png" width="50" height="50" style="display:none;">
</div>
and the js used as shown above, I suggest to use $('.mainmenublok').css('width', mbwsize+'px'); instead of $('#mainmenublok').css('width', mbwsize+'px');. Dots are used to indicate classes in CSS, as hashtags are used to indicate ID's.
You could use mediaqueries or device.js?
The way you are trying to achieve by script.... Is okay but in some browser it may give you bugs ... better you try with any of the css frameworks like twitter bootstrap its not really huge.... the your site will be responsive as according to your device....
Lets say that we have an image uploaded by the user, the upload script limits the mb but not the image size (so could be any proportion, 600X200,200X350, and so...).
Im already showing this image in one part on my site using the twitter bootstrap image handler written on css, thats good for a profile picture, the problem is that now I want that image to be a cover (like facebook/twitter cover image), my site is responsive so the width of the cover is 900px or 100% if the screen resolution is less than 900px wide. The height is always fixed to 200px. So I know there is a way to control the correct image display using CSS (maybe with jquery too) but Im not a front-end dev, Im a php dev and I dont want to use server side scripts for doing this. So im looking for suggestions or pieces of codes (css, javascript) to start with, I belive that it have to be an already made solution for this, but I dont find any on google. Thanks for any advice!
I would definitely not advise to use a css-only solution. Not even a client-side solution if the uploaded pictures can have any resolution. You want to use a php script to save resized versions of the uploaded images and serve those to the client. Either as a block's background-image and use css (not cross browser) or as an img tag and use js to resize.
css:
.myselector{
background-size: cover;
}
or js (jquery):
$(function(){
var containers = $('.myselector'), w = $(window);
function onResize(){
//resize code
containers.each(function(){
var $this = $(this),
w = $this.width(),
h = $this.height(),
ratio = w/h,
$img = $('img',$this); // assuming there is only one img in each container
$img.css({'width':'auto','height':'auto'});
var iw = $img.width(), ih = $img.height(), iratio = iw/ih;
if(iratio>ratio){
$img.css({
height:'100%',
width:'auto',
marginLeft: (w-iw*(h/ih))/2
});
}
else{
$img.css({
width:'100%',
height:'auto',,
marginTop: (h-ih*(w/iw))/2
});
}
});
}
w.bind('resize',onResize);
//resize on each image load event
$('img',containers).bind('load',onResize);
onResize();
});
Here is a working fiddle : http://jsfiddle.net/kHxd2/2/
The image's onload listener might need tweeking to react when cached images are rendered in IE: http://css-tricks.com/snippets/jquery/fixing-load-in-ie-for-cached-images/
Also you might want to set css rules for rare non-js browsers... (.myselector img{width:100%;})
EDIT : container css:
.myselector{
width: 100%;
max-width: 900px;
height: 200px;
margin: auto; /* centering */
overflow: hidden;
}
see updated fiddle: http://jsfiddle.net/kHxd2/3/
The best solution is to embed the image containers in a main wrapper div and apply the above css rules to that big container.
Here is some useful code to take care of server-side resizing : http://www.9lessons.info/2009/03/upload-and-resize-image-with-php.html
You have to put this image as background-image, and then use style:
background-image: url(url/to/your/image.png);
background-size: cover;
There is a property in css3 called as background-size:cover; and background-size:contain;. You might want to use them to suit your needs.
contain
Specifies that the background image should be scaled to be as large as possible while ensuring both its dimensions are less than or equal to the corresponding dimensions of the background positioning area.
cover
Specifies that the background image should be scaled to be as small as possible while ensuring both its dimensions are greater than or equal to the corresponding dimensions of the background positioning area.
is there a way to embedd youtube video as a background of a web page with html, css and javascript with the actual site content on top? how?
basically, it should be a video that auto plays, is muted (but the volume can be turned up by the visitor) and the site should work well being on top of it (the site is minimal so most of the video should be visible at all times). the site is minimal enough that no scroll bars would be visible by default in most browsers and the video should be 100% width and height.
examples? links?
tried Google but couldn't find it.
also it should work for videos not on youtube.
html5 and css3 preferred :)
I REALLY NEED A LIVE EXAMPLE SOMEWHERE (or as close to) because i tried it all (as available via google and failed)
also, related - there doesn't seem to be (as per my own research) any way of slowing down the play of youtube videos (for example: 24 times slower) - true / false?
You have probably found a solution by now but just in case you haven't...have you tried http://www.seanmccambridge.com/tubular/ ?
<div style="position: fixed; z-index: -99; width: 100%; height: 100%">
<iframe frameborder="0" height="100%" width="100%"
src="https://youtube.com/embed/ID?autoplay=1&controls=0&showinfo=0&autohide=1">
</iframe>
</div>
// Replace ID with the actual ID of your YouTube video
http://www.labnol.org/internet/youtube-video-background/27933/
you got this library as well:
http://florian-chapon.fr/dev/youtube-background/
the only thing you have to do, is include the js file, and put this script on your "body":
$(document).ready(function() {
ytbg("vQWlNALvbhE", 0, 17, 1);
});
As an explanation:
ytbg("video link", starttime, endtime, volume).
for completeness sake adding http://okfoc.us/okvideo/ here. Also does Vimeo.
There are two ways to answer this question:
Set the flash player's wmode to transparent, put it in an absolute div with a low z-index. Put the content in another absolute div with a higher z-index.
Don't do it. Seriously. Don't put a movie behind the site's main content. You are aliening your customer base, making the site hare to view and read, and violating about a dozen or two other guidelines in good site design. Why not put the video inside the flow of the document where it belongs instead?
Well you could absolute position the tag or the , use CSS to set the height and width. Use javascript to simulate clicking on the button. set the element zIndex to the background.
Hi, as tubular is quite suffisticated, i extracted the necessary code
for you.
html code:
<div id="player-container" style="overflow: hidden; position: absolute; width: 100%; height: 100%;">
<div id="player" style="position: absolute">
</div>
here comes the complete youtube API cover style stuff, extracted from
tubular. jquery is needed. Also the standard youtube html5 iframe api
code must be included - as given here:
https://developers.google.com/youtube/iframe_api_reference#Getting_Started
var ratio = 16 / 9;
window.onPlayerReady = function (e) {
resize();
}
$(window).on('resize', function () {
resize();
})
var resize = function () {
console.log("resize");
var heightcorrection = 0,
width = $(window).width(),
pWidth, // player width, to be defined
height = $(window).height() - heightcorrection,
pHeight, // player height, tbd
$videoPlayer = $('#player');
if (width / ratio < height) { // if new video height < window height (gap underneath)
pWidth = Math.ceil(height * ratio); // get new player width
$videoPlayer.width(pWidth).height(height).css({
left: (width - pWidth) / 2,
top: 0
}); // player width is greater, offset left; reset top
} else { // new video width < window width (gap to right)
pHeight = Math.ceil(width / ratio); // get new player height
$videoPlayer.width(width).height(pHeight).css({
left: 0,
top: (height - pHeight) / 2
}); // player height is greater, offset top; reset left
}
}