I have a gallery of images in a scrolling layout on a website. On PC, all the images show. On Android, all the images show. On iPhone, using the same browser as on Android (Chrome or Firefox), when scrolling through the images some of them don't appear, or only half-appear until they are scrolled offscreen and then back again. The images still exist in the layout and can still be tapped to open the lightbox. Why is this happening? I'm using lozad.js to try to solve this problem (because I thought it might be just loading too much data at once) but the problem existed before I implemented lozad. Here's my code for each image:
.gallery {
padding-top: 13px;
z-index: 3;
position: relative;
overflow: scroll;
-webkit-overflow-scrolling: touch;
height: calc(100vh - 13px);
}
.thumbnail {
min-height: 25%;
width: 25%;
margin: 10px;
border-radius: 10px;
}
/** LIGHTBOX MARKUP **/
.lightbox {
/** Default lightbox to hidden */
display: none;
/** Position and style */
position: fixed;
z-index: 999;
width: 100%;
height: 100%;
text-align: center;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.8);
}
.lightbox img {
/** Pad the lightbox image */
max-width: 90%;
max-height: 80%;
margin-top: 5%;
}
.lightbox:target {
/** Remove default browser outline */
outline: none;
/** Unhide lightbox **/
display: block;
}
<div id="mobile" class="gallery">
<!-- thumbnail image wrapped in a link -->
<a href="#img1-mobile">
<img src="thumb/lo/1.jpg" data-src="thumb/hi-mobile/1.jpg" class="lozad thumbnail">
</a>
<!-- lightbox container hidden with CSS -->
<a href="#_" class="lightbox" id="img1-mobile">
<img src="img/lo/1.jpg" data-src="img/hi/1.jpg" class="lozad">
</a>
<!-- thumbnail image wrapped in a link -->
<a href="#img2-mobile">
<img src="thumb/lo/2.jpg" data-src="thumb/hi-mobile/2.jpg" class="lozad thumbnail">
</a>
<!-- lightbox container hidden with CSS -->
<a href="#_" class="lightbox" id="img2-mobile">
<img src="img/lo/2.jpg" data-src="img/hi/2.jpg" class="lozad">
</a>
<!-- thumbnail image wrapped in a link -->
<a href="#img3-mobile">
<img src="thumb/lo/3.jpg" data-src="thumb/hi-mobile/3.jpg" class="lozad thumbnail">
</a>
<!-- lightbox container hidden with CSS -->
<a href="#_" class="lightbox" id="img3-mobile">
<img src="img/lo/3.jpg" data-src="img/hi/3.jpg" class="lozad">
</a>
...
</div>
Here’s a hacky but effective fix:
#mobile img {
transform: translate3d(0, 0, 0);
}
“But why does this work?”
Because it’s a mobile browser engine, WebKit WebCore cuts a lot of corners when performing Composite and Paint stages. It does this in the name of battery life, and generally that’s a great tradeoff. By applying a 3D transformation (even a null one), these two stages are passed off to the hardware-accelerated (read: more power hungry) graphics engine.
In your case, this corner-cutting occurs when an image is off-screen up until the point it’s interacted with by the user (clicking on it does the trick).
Since these calls only occur when the page requires a repaint (scrolling & zooming mostly), the penalty to your users battery-wise should be minimal.
It turns out mobile versions of WebKit have struggled with image-heavy pages for almost 6 years. The solution there, incidentally, is effectively the same. Sometimes the old ways still work best :p
Related
So I have the external links all set up, and the badges on the website, but the main problem I am currently experience is making these align vertically (the Google play badge is slightly moved to the right underneath the apple store)
Downloadable badges alignment issue
Below is currently the code that I have set up for these two badges -- what exactly do I have to change to make the Google play badge align vertically with the Apple store badge? I feel like I have tried mostly everything, but am still very confused.
<img src="https://tools.applemediaservices.com/api/badges/download-on-the-app-store/black/en-us?size=250x83&releaseDate=1276560000&h=7e7b68fad19738b5649a1bfb78ff46e9" alt="Download on the App Store" style="border-radius: 15px; width: 150px; height: 90px;">
<a href='https://play.google.com/store/apps/details?id=com.stagescycling.stages'><img style="width:164px;margin-top:-30px;" alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png'/></a>
Edit: Not really sure why the code snippet is not showing them aligned with the Apple store on top and the Google play store on the bottom -- reference the screenshot for the correct orientation.
EDITED: ADDED A VERTICAL STACKING OPTION
TL;DR. Remove inline styles. Apply alignment styling to their parents.
See below for code snippet. Inline styles could make it very difficult to build a consistent definitions throughout and also likely difficult to debug.
Here, I've added a simple vertical alignment by adding flex and align-items to its parent. The images differ in their sizes and transparent margins around, which is simply addressed by their width in CSS.
.app-icons {
display: flex;
align-items: center;
}
.vertical {
width: 300px;
flex-direction: column;
}
.android {
width: 150px;
.apple {
width: 164px;
}
<h2>Vertical Stacked</h2>
<div class="app-icons vertical">
<a href="https://apps.apple.com/app/id1551353775">
<img
class="apple"
src="https://tools.applemediaservices.com/api/badges/download-on-the-app-store/black/en-us?size=250x83&releaseDate=1276560000&h=7e7b68fad19738b5649a1bfb78ff46e9"
alt="Download on the App Store">
</a>
<a href='https://play.google.com/store/apps/details?id=com.stagescycling.stages'>
<img
class="android"
alt='Get it on Google Play'
src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' />
</a>
</div>
<h2>Horizontally Presented</h2>
<div class="app-icons">
<a href="https://apps.apple.com/app/id1551353775">
<img
class="apple"
src="https://tools.applemediaservices.com/api/badges/download-on-the-app-store/black/en-us?size=250x83&releaseDate=1276560000&h=7e7b68fad19738b5649a1bfb78ff46e9"
alt="Download on the App Store">
</a>
<a href='https://play.google.com/store/apps/details?id=com.stagescycling.stages'>
<img
class="android"
alt='Get it on Google Play'
src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' />
</a>
</div>
The problem is not about alignment, it happens that your Google Store image is a PNG with a transparent border around it. The border don't shows (because it is transparent), but use the space. You have to cut the border out using a image editing program like photoshop or Photopea Online Image Editor, but if absolutelly necessary to use the image as is on your code, copy and paste the snippet bellow to achive your result.
<style>
.storeLink {
position: relative;
display: inline-block;
width: 240px;
height: 80px;
border-radius: 16px;
overflow: hidden;
background-color: black;
}
.storeLink > img {
--width: 100%;
position: absolute;
width: var(--width);
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
<img src="https://tools.applemediaservices.com/api/badges/download-on-the-app-store/black/en-us?size=250x83&releaseDate=1276560000&h=7e7b68fad19738b5649a1bfb78ff46e9" alt="Download on the App Store" >
<img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' style="--width: 128%";/>
What i'm trying to achieve
example of the closed version /
example of the opened version
At the top of the page in a 'fixed' header, i have a 'search' button next to a 'toggle' for the main menu. The header-search div (magnifying glass) is positioned next to the menu toggler (green). A form is currently positioned 'absolute' within the header to take up the full width of the header minus the padding on each side and its controls (search and toggler) as follows:
styles from header
.header {
top: 0;
left: 0;
width: 100%;
position: fixed;
background-color: var(--color-primary-700);
}
styles from header__aux
.header__aux {
display: flex;
column-gap: 1rem;
flex-flow: nowrap row;
}
.header-search {
display: block;
position: static;
}
.header-search__form {
top: 1.5rem;
height: 4rem;
overflow: hidden;
position: absolute;
left: var(--g-gutter);
width: calc(100% - (7rem + (var(--g-gutter)*2)));
}
.header-search__form-label {
top: -99.9rem;
left: -99.9rem;
color: inherit;
position: absolute;
}
.header-search__form.is-active
.header-search__form-input {
transform: translateX(0%);
}
.header-search__form-input {
width: 100%;
height: 4rem;
padding: 0 1.2em;
transform: translateX(100%);
border: .2rem solid #8097b3;
border-top-left-radius: 2rem;
border-bottom-left-radius: 2rem;
transition: transform 1s ease-in-out
background-color: var(--color-primary-700);
}
A input field inside this form is given 100% width and then using transform: translateX(100%) pushed completely to the right outside the overflow of the form (which retains it's width as set above). When a user presses the 'search' button a class is-active sets this transform: translateX(100%) to 0 and the input field should slide (from the right) to it's original position 100% of the width as seen in this image.
What this looks like in HTML
<header class="header section">
<div class="header__container container">
<a class="header__brand" href="#" aria-label="x">
<!-- svg brand -->
</a>
<div class="header__navs" id="headerNavs">
<div class="header__mask">
<ul id="headerMenu" class="header-menu">
</ul> <div class="header__langs header-langs">
Language
</div>
</div>
</div>
<div class="header__aux">
<div class="header__search header-search">
<button aria-label="Open of sluit het invoerveld voor een zoekopdracht" class="header-search__toggle" id="headerSearchToggle" aria-pressed="false" role="button" tabindex="0">
<i id="headerSearchIcon" class="far fa-search"></i>
</button>
<form class="header-search__form" action="/" id="headerSearchForm" role="search" method="get">
<label class="header-search__form-label" for="headerSearchInput">Zoeken</label>
<div class="header-search__form-slide">
<input placeholder="Zoeken …" required="" class="header-search__form-input" id="headerSearchInput" minlength="2" type="search" value="" name="s">
</div>
</form>
</div>
<a aria-label="" class="header__toggle header-toggle" aria-controls="headerNavs" aria-expanded="false" id="headerToggle" href="#">
Toggle
</a>
</div>
</div>
</header>
The problem
When opening the 'search' the input immediately jumps to the end of the animation which is seen in the example of the opened version (top) and then continues moving left, constantly correcting it's position back to what is seen in the image causing a weird 'flickering' effect usually in this position. Sliding the input 'back' to the right works perfectly.. What's even weirder is that it sometimes does work correctly for a few attempts once i've been on the page for a while. Then suddenly it breaks again.
What i've tried
Different types of browsers, including checking it on my own mobile device (not in the dev tools)
Giving the input the same fixed width as the parent
Removing a translateY on the parent and reverting to 'top' top position it in the vertical center
Adding 1 or multiple parents to the input to force it to inherit that width
As mentioned in a comment, adding transform:translateZ(0.1px); to force rendering using the GPU
What works, but i can't explain
Removing the overflow on the parent form element works and allows the animation to play smoothly, but that shows the input behind the element as seen in this image
I can think of some ways to make this look better, but i just really want to know what i'm missing. I believe i've done these types of simple animations 1000s of times now. A parent with overflow, hiding a child that's translated over.. or perhaps i'm mistaken. Hopefully someone can make sense of this - many thanks if you've taken the time to do so :)
I found cool css to create lightbox. It uses :target to show lightbox div. I tried in in code pen and it works fine, however on my site it doesn't show anything. I can't find what else in my code is blocking it from showing. Here's the basic code:
HTML:
<a href="#img2" class="image">
<img src="https://d2d00szk9na1qq.cloudfront.net/Product/2c6b113d-e972-42cc-a2de-f5dcf1c82e95/Images/Large_0297791.jpg">
</a>
<a href="#_" class="lightbox" id="img2">
<img src="https://d2d00szk9na1qq.cloudfront.net/Product/2c6b113d-e972-42cc-a2de-f5dcf1c82e95/Images/Large_0297791.jpg">
</a>`
CSS:
.lightbox {
display: none;
position: fixed;
z-index: 999;
width: 100%;
height: 100%;
text-align: center;
top: 0;
left: 0;
background: rgba(0,0,0,0.8)
}
.lightbox img {
max-width: 90%;
max-height: 80%;
margin-top: 2%;
}
.lightbox:target {
outline: none;
display: block;
}
(Codepen: http://codepen.io/anon/pen/jrBrmp)
and here's my site: http://test.fulfeal.co.uk/how-to/ Thanks in advance.
Aleksander
Something in your site installation is preventing the URL from changing when the hashtag links are clicked. The :target selector works on the hashtag in the URL.
You will see if you navigate directly to http://test.fulfeal.co.uk/how-to/#img1 the image pops up as expected. So nothing is wrong with your CSS, the issue is with the URL routing on your site.
In codepen the URL isn't changing because the demo box at the bottom has its own iframe, and it is being updated with the link.
Your site url is been routed. Two ways to solve the issue
You are using wordpress framework for your site, so go to the wordpress content admin panel and change your url type.
OR
Add below code at the end of your site.
<script>
$(function(){
$(".image").on("click",function(){
var image = $(this).attr("href");
$(image).show();
});
});
</script>
I have a brand logo on Bootstrap Nav.
<a href="http://localhost/SGW" class="logo hero_logo">
<img class="img-responsive" src="http://localhost/SGW/wp-content/uploads/2015/09/unnamed.png" alt="Sai Gon Works">
</a>
Original size of images is 1909 x 406. And I have a style for
.hero_logo {
display: block;
position: absolute;
padding-left: 25px;
padding-top: 15px;
z-index: 100;
width: 300px;
}
But when i refresh page, my logo is expand until my page load done. You can see this issue in my video: https://www.youtube.com/watch?v=MQAZmyWRfbo&feature=youtu.be
How to fix it?
Add your hero_logo class to <img> tag, not <a> and it should work. Or add width=300 to <img> tag.
I have an image, and on top of that image is another smaller image. When the first image is clicked, the second one appears, and it disappears when the first image is clicked again. My problem is when the second image appears over the first one, it makes the area that it covers of the first image unclickable. Is it possible to make it so the first image can be clicked through the second image?
This is the HTML for the second image (it's generated in PHP):
Echo '<img src="images/tick.png" id="tick' . $i .'" class="hidden" style="position: absolute; top: 0px; left: 70%;"/>';
Simply put both images in a container div, and attach the click event handler to that instead of the bigger image. This way you can simply make use of event bubbling (which isn't available on the bigger image since it cannot have child elements, such as the smaller image).
Find a working solution here:
https://jsfiddle.net/6nnwy3xw/
$(document).ready(function() {
$('.imgcontainer').on('click', function() {
$(this).toggleClass('toggleImg');
});
})
.imgcontainer {
height: 300px;
width: 300px;
position: relative;
}
.imgcontainer img:first-child {
display: block;
height: 300px;
width: 300px;
}
.imgcontainer img+img {
position: absolute;
top: 50px;
left: 50px;
opacity: 0;
transition-duration: 0.3s;
}
.imgcontainer.toggleImg img+img {
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="imgcontainer">
<img src="http://lorempixel.com/300/300" />
<img src="http://lorempixel.com/200/200" />
</div>
I'm assuming your use-case is some kind of checkbox replacement element? In this case, this may also be of interest to you:
Use images like checkboxes
If that is the case, I'd make the surrounding diva label instead, so it also automatically checks your (probably hidden) real checkbox.
If I understand the issue you're describing properly, you could try turning pointer-events off for the second image, that is often displayed over the click-target:
.two { pointer-events: none; }
Note that this is only supported with HTML in Internet Explorer 11 and up (as well as in Chrome and Firefox). For SVG, support was available in IE 9. That may suffice for a work-around if needed.
Fiddle: http://jsfiddle.net/tbqxjp19/
For better support you should move your handler to an element that will not be obstructed, and as such will always work to toggle the visibility of the second image:
<div class="images">
<img src="http://placehold.it/100x100" class="one" />
<img src="http://placehold.it/100x100/000000" class="two" />
</div>
document.querySelector( ".images" ).addEventListener( "click", function () {
this.classList.toggle( "toggled" );
});
The above simply binds a handler to click events on the .images container, toggling a class that will hide and/or reveal the second image, given the following:
.toggled .two {
opacity: .1;
}
Fiddle: http://jsfiddle.net/tbqxjp19/1/
Try this , if you are fine with jquery solution.
HTML
<img src="images/large.png" class ="image" id="image1" style="position: absolute; top: 0px; left: 0px;" />
<img src="images/small.png" id="image2" class ="image" style="position: absolute; top: 0px; left: 0px; z-index:10;" />
css
.hiddenimage{
display:none;
}
JQuery
$(".image").click(function(){
("#image2").toggleClass("hiddenimage");
})