Tag: Modal

Creating a Modal Image Gallery With Bootstrap Components

Have you ever clicked on an image on a webpage that opens up a larger version of the image with navigation to view other photos?

Some folks call it a pop-up. Others call it a lightbox. Bootstrap calls it a modal. I mention Bootstrap because I want to use it to make the same sort of thing. So, let’s call it a modal from here on out.

Why Bootstrap? you might ask. Well, a few reasons:

  • I’m already using Bootstrap on the site where I want this effect, so there’s no additional overhead in terms of loading resources.
  • I want something where I have complete and easy control over aesthetics. Bootstrap is a clean slate compared to most modal plugins I’ve come across.
  • The functionality I need is fairly simple. There isn’t much to be gained by coding everything from scratch. I consider the time I save using the Bootstrap framework to be more beneficial than any potential drawbacks.

Here’s where we’ll end up:

Let’s go through that, bit by bit.

Step 1: Create the image gallery grid

Let’s start with the markup for a grid layout of images. We can use Bootstrap’s grid system for that.

<div class="row" id="gallery">   <div class="col-12 col-sm-6 col-lg-3">     <img class="w-100" src="/image-1">   </div>   <div class="col-12 col-sm-6 col-lg-3">     <img class="w-100" src="/image-2">   </div>   <div class="col-12 col-sm-6 col-lg-3">     <img class="w-100" src="/image-3">   </div>   <div class="col-12 col-sm-6 col-lg-3">     <img class="w-100" src="/image-4">   </div> </div>

Now we need data attributes to make those images interactive. Bootstrap looks at data attributes to figure out which elements should be interactive and what they should do. In this case, we’ll be creating interactions that open the modal component and allow scrolling through the images using the carousel component.

About those data attributes:

  1. We’ll add data-toggle="modal"  and data-target="#exampleModal" to the parent element (#gallery). This makes it so clicking anything in the gallery opens the modal. We should also add the data-target value (#exampleModal) as the ID of the modal itself, but we’ll do that once we get to the modal markup.
  2. Let’s add data-target="#carouselExample"  and a data-slide-to attribute to each image. We could add those to the image wrappers instead, but we’ll go with the images in this post. Later on, we’ll want to use the data-target value (#carouselExample) as the ID for the carousel, so note that for when we get there. The values for data-slide-to are based on the order of the images.

Here’s what we get when we put that together:

<div class="row" id="gallery" data-toggle="modal" data-target="#exampleModal">   <div class="col-12 col-sm-6 col-lg-3">     <img class="w-100" src="/image-1.jpg" data-target="#carouselExample" data-slide-to="0">   </div>   <div class="col-12 col-sm-6 col-lg-3">     <img class="w-100" src="/image-2.jpg" data-target="#carouselExample" data-slide-to="1">   </div>   <div class="col-12 col-sm-6 col-lg-3">     <img class="w-100" src="/image-3.jpg" data-target="#carouselExample" data-slide-to="2">   </div>   <div class="col-12 col-sm-6 col-lg-3">     <img class="w-100" src="/image-4.jpg" data-target="#carouselExample" data-slide-to="3">   </div> </div>

Interested in knowing more about data attributes? Check out the CSS-Tricks guide to them.

Step 2: Make the modal work

This is a carousel inside a modal, both of which are standard Bootstrap components. We’re just nesting one inside the other here. Pretty much a straight copy-and-paste job from the Bootstrap documentation.

Here’s some important parts to watch for though:

  1. The modal ID should match the data-target of the gallery element.
  2. The carousel ID should match the data-target of the images in the gallery.
  3. The carousel slides should match the gallery images and must be in the same order.

Here’s the markup for the modal with our attributes in place:

<!-- Modal markup: https://getbootstrap.com/docs/4.4/components/modal/ --> <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-hidden="true">   <div class="modal-dialog" role="document">     <div class="modal-content">       <div class="modal-header">         <button type="button" class="close" data-dismiss="modal" aria-label="Close">           <span aria-hidden="true">×</span>         </button>       </div>       <div class="modal-body">                <!-- Carousel markup goes here --> 
       <div class="modal-footer">         <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>       </div>     </div>   </div> </div>

We can drop the carousel markup right in there, Voltron style!

<!-- Modal markup: https://getbootstrap.com/docs/4.4/components/modal/ --> <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-hidden="true">   <div class="modal-dialog" role="document">     <div class="modal-content">       <div class="modal-header">         <button type="button" class="close" data-dismiss="modal" aria-label="Close">           <span aria-hidden="true">×</span>         </button>       </div>       <div class="modal-body">                <!-- Carousel markup: https://getbootstrap.com/docs/4.4/components/carousel/ -->       <div id="carouselExample" class="carousel slide" data-ride="carousel">           <div class="carousel-inner">             <div class="carousel-item active">               <img class="d-block w-100" src="/image-1.jpg">             </div>             <div class="carousel-item">               <img class="d-block w-100" src="/image-2.jpg">             </div>             <div class="carousel-item">               <img class="d-block w-100" src="/image-3.jpg">             </div>             <div class="carousel-item">               <img class="d-block w-100" src="/image-4.jpg">             </div>           </div>           <a class="carousel-control-prev" href="#carouselExample" role="button" data-slide="prev">             <span class="carousel-control-prev-icon" aria-hidden="true"></span>             <span class="sr-only">Previous</span>           </a>           <a class="carousel-control-next" href="#carouselExample" role="button" data-slide="next">             <span class="carousel-control-next-icon" aria-hidden="true"></span>             <span class="sr-only">Next</span>           </a>         </div>       </div>        <div class="modal-footer">         <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>       </div>     </div>   </div> </div>

Looks like a lot of code, right? Again, it’s basically straight from the Bootstrap docs, only with our attributes and images.

Step 3: Deal with image sizes

This isn’t necessary, but if the images in the carousel have different dimensions, we can crop them with CSS to keep things consistent. Note that we’re using Sass here.

// Use Bootstrap breakpoints for consistency. $  bootstrap-sm: 576px; $  bootstrap-md: 768px; $  bootstrap-lg: 992px; $  bootstrap-xl: 1200px; 
 // Crop thumbnail images. #gallery {   img {     height: 75vw;     object-fit: cover;          @media (min-width: $  bootstrap-sm) {       height: 35vw;     }          @media (min-width: $  bootstrap-lg) {       height: 18vw;     }   } } 
 // Crop images in the coursel .carousel-item {   img {     height: 60vw;     object-fit: cover;          @media (min-width: $  bootstrap-sm) {       height: 350px;     }   } }

Step 4: Optimize the images

You may have noticed that the markup uses the same image files in the gallery as we do in the modal. That doesn’t need to be the case. In fact, it’s a better idea to use smaller, more performant versions of the images for the gallery. We’re going to be blowing up the images to their full size version anyway in the modal, so there’s no need to have the best quality up front.

The good thing about Bootstrap’s approach here is that we can use different images in the gallery than we do in the modal. They’re not mutually exclusive where they have to point to the same file.

So, for that, I’d suggest updating the gallery markup with lower-quality images:

<div class="row" id="gallery" data-toggle="modal" data-target="#exampleModal">   <div class="col-12 col-sm-6 col-lg-3">     <img class="w-100" src="/image-1-small.jpg" data-target="#carouselExample" data-slide-to="0">      <!-- and so on... --> </div>

That’s it!

The site where I’m using this has already themed Bootstrap. That means everything is already styled to spec. That said, even if you haven’t themed Bootstrap you can still easily add custom styles! With this approach (Bootstrap vs. plugins), customization is painless because you have complete control over the markup and Bootstrap styling is relatively sparse.

Here’s the final demo:

The post Creating a Modal Image Gallery With Bootstrap Components appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,

Weekly Platform News: WebAPK Limited to Chrome, Discernible Focus Rectangles, Modal Window API

In this week’s roundup: “Add to home screen” has different meanings in Android, Chrome and Edge add some pop to focus rectangles on form inputs, and how third-party sites may be coming to a modal near you.

Let’s get into the news.

WebAPKs are not available to Firefox on Android

On Android, both Chrome and Firefox have an “Add to home screen” option, but while Firefox merely adds a shortcut for the web app to the user’s home screen, Chrome actually installs the web app (as long as it meets the PWA install criteria) via a WebAPK.

Progressive Web Apps installed in such a way are added to the device’s app drawer, and URLs that are within the PWA’s scope (as specified in its manifest) open in the PWA instead of the default browser.

Tiger Oakes who is implementing PWA-related features at Mozilla, explains why Firefox cannot install PWAs on Android: “WebAPK is not available to us since we don’t own an app store like Google Play and Galaxy Apps.”

(via Tiger Oakes)

More accessible focus rectangles are coming to Chrome and Edge

Microsoft and Google have made accessibility improvements to various form controls. The two main changes are the larger touch targets on the time and date inputs, and the redesigned focus rectangles that are now easily discernible on any background.

The updated form controls are available in the preview version of Edge. Mac users may have to manually enable the “Web Platform Fluent Controls” flag on the about:flags page.

(via Microsoft Edge Dev)

A newly proposed API for loading third-parties in modal windows

The proposed Modal Window API would allow a website to load another website in a modal window (in a top-level browsing context) for the purposes of authentication, payments, sharing, access to third-party services, etc.

Only a single modal window would be allowed at a time, and the two websites could communicate with each other via message events (postMessage method).

This API is intended as a better alternative to existing methods, such as pop-ups, which can be confusing to users and blocked by browsers, and redirects, which cause the original context to be torn down and recreated (or completely lost in the case of an error in the third-party service).

(via Adrian Hope-Bailie)

More news…

Read even more news in my weekly Sunday issue that can be delivered to you via email every Monday morning.

More News →

The post Weekly Platform News: WebAPK Limited to Chrome, Discernible Focus Rectangles, Modal Window API appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , , , , ,
[Top]

Prevent Page Scrolling When a Modal is Open

Please stop me if you’ve heard this one before. You open a modal, scroll through it, close it, and wind up somewhere else on the page than you were when you opened the modal.

That’s because modals are elements on a page just like any other. It may stay in place (assuming that’s what it’s meant to do) but the rest of page continues to behave as normal.

See the Pen
Avoid body scrollable in safari when modal dialog shown
by Geoff Graham (@geoffgraham)
on CodePen.

Sometimes this is a non-issue, like screens that are the exact height of the viewport. Anything else, though, we’re looking at Scroll City. The good news is that we can prevent that with a sprinkle of CSS (and JavaScript) trickery.

Let’s start with something simple

We can make a huge dent to open-modal-page-scrolling by setting the height of the entire body to the full height of the viewport and hiding vertical overflow when the modal is open:

body.modal-open {   height: 100vh;   overflow-y: hidden; }

That’s good and all, but if we’ve scrolled through the <body> element before opening the modal, we get a little horizontal reflow. The width of the viewport is expanded about 15 pixels more, which is exactly the with of the scroll bar.

See the Pen
Avoid body scrollable in safari when modal dialog shown
by Geoff Graham (@geoffgraham)
on CodePen.

Let’s adjust the right padding of the body a bit to avoid that.

body {   height: 100vh;   overflow-y: hidden;   padding-right: 15px; /* Avoid width reflow */ }

Note that the modal needs to be shorter than the height of the viewport to make this work. Otherwise, the scroll bar on the body will be necessary.

Great, now what about mobile?

This solution works pretty great on desktop as well as Android Mobile. That said, Safari for iOS needs a little more love because the body still scrolls when a modal is open when tapping and moving about the touchscreen.

We can set the body to a fixed position as a workaround:

body {   position: fixed; }

Works now! The body will not respond when the screen is touched. However, there’s still a “small” problem here. Let’s say the modal trigger is lower down the page and we click to open it up. Great! But now we’re automatically scrolled back up to the top of the screen, which is just as disorientating as the scrolling behavior we’re trying to resolve.

See the Pen
Avoid body scrollable in safari when modal dialog shown
by Geoff Graham (@geoffgraham)
on CodePen.

Boo!

That’s why we’ve gotta turn to JavaScript

We can use JavaScript to avoid the touch event bubble. We all know there should be a backdrop layer when a modal is open. Unfortunately, stopPropagation is a little awkward with touch in iOS. But preventDefault works well. That means we have to add event listeners in every DOM node contained in the modal — not just on the backdrop or the modal box layer. The good news is, many JavaScript libraries can do this, including good ol’ jQuery.

Oh, and one more thing: What if we need scrolling inside the modal? We still have to trigger a response for a touch event, but when reaching the top or bottom of the modal, we still need to prevent bubbling. Seems very complex, so we’re not totally out of the woods here.

Let’s enhance the fixed body approach

This is what we were working with:

body {   position: fixed; }

If we know the top of the scroll location and add it to our CSS, then the body will not scroll back to the top of the screen, so problem solved. We can use JavaScript for this by calculating the scroll top, and add that value to the body styles:

// When the modal is shown, we want a fixed body document.body.style.position = 'fixed'; document.body.style.top = `-$  {window.scrollY}px`;  // When the modal is hidden, we want to remain at the top of the scroll position document.body.style.position = ''; document.body.style.top = '';

This works, but there’s still a little leakage here after the modal is closed. Specifically, it appears that the page already loses its scroll position when the modal is open and the body set to be fixed. So we have to retrieve the location. Let’s modify our JavaScript to account for that.

// When the modal is hidden... const top = document.body.style.top; document.body.style.position = ''; document.body.style.top = ''; window.scrollTo(0, parseInt(scrollY || '0') * -1);

That does it! The body no longer scrolls when a modal is open and the scroll location is maintained both when the modal is open and when it is closed. Huzzah!

See the Pen
Avoid body scrollable in safari when modal dialog shown
by Geoff Graham (@geoffgraham)
on CodePen.

The post Prevent Page Scrolling When a Modal is Open appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]