How to show HTML video overlays with VideoJS in fullscreen? - javascript

I have a quiz video overlay that shows up nicely when the videojs player is in standard mode: https://jsfiddle.net/c4nxdf38/
However, when entering fullscreen it disappears (probably behind the video).
I found an obsolete solution which specifies the z-index of the overlay to the maximum. It is not working in the latest Chrome and Firefox.
I found another solution to do the fullscreen with the parent, not the videoplayer itself, but it's not working with the videojs player setup.
Then I found a promising solution how to make overlay elements appear on fullscreen by setting position:absolute; and tried to implement it without success: https://jsfiddle.net/5Lqfyzh4/
HTML from my last attempt (see fiddle):
<div id="main-container">
<div id="overlays-wrap">
<div class="overlay-item" data-overlayid="59" data-time="41">
<p class="vo-question">
Welche Zahl ist die Summe bei 3 + 50 = 53?
</p>
<div class="vtask-choices-wrap">
<div class="vtask-choice-item">
<input class="vtask-choice" type="radio" name="quiz" id="59-a1" value="1" data-correct="0">
<label class="radio-tile" for="59-a1">
<span class="radio-tile-label">
3
</span>
</label>
</div>
<div class="vtask-choice-item">
<input class="vtask-choice" type="radio" name="quiz" id="59-a2" data-correct="0">
<label class="radio-tile" for="59-a2">
<span class="radio-tile-label">
50
</span>
</label>
</div>
<div class="vtask-choice-item">
<input class="vtask-choice" type="radio" name="quiz" id="59-a3" value="3" data-correct="1">
<label class="radio-tile" for="59-a3">
<span class="radio-tile-label">
53
</span>
</label>
</div>
</div> <!-- vtask-choices-wrap -->
<a class="buttonb vtask-btn-continue">Continue</a>
</div> <!-- overlay-item -->
</div>
<div id="videowrapper">
<video id="videoplay" class="video-js vjs-default-skin" controls preload="metadata" width="854" height="480" poster="" autoplay="true">
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
</video>
</div>
</div>
Javascript:
$(document).ready(function() {
var options = {
playbackRates: [1, 1.5, 2],
muted: true,
};
video = videojs('videoplay', options);
video.ready(function() {
/*
this.on('fullscreenchange',function() {
console.log('fullscreen event');
});
*/
}); // end video.ready
// OVERLAY PREPARE
// $('#overlays-wrap, .overlay-item').hide();
// OVERLAY INTERACTION
$('.radio-tile').click( function() {
// only show if not yet submitted, prevents submit then click again on radio-tile which would show the vtask-btn-continue
var submitted = $(this).closest('.overlay-item').hasClass('overlay-submitted');
if(!submitted)
{
$(this).parent().parent().next('.vtask-btn-continue').css('visibility', 'visible');
// make sure we check the radio button
$(this).prev('.vtask-choice').prop('checked', true);
}
});
$('.vtask-btn-continue').click( function() {
// hide continue button
$(this).css('visibility', 'hidden');
var overlay = $(this).closest('.overlay-item'); // $(this).parent()
overlay.hide();
});
}); // END ready
CSS:
#overlays-wrap {
position: absolute;
width: 100%;
height: 100%;
max-height:460px;
left: 0;
top: 0;
z-index: 2147483647;
}
.overlay-item {
position: absolute;
top: 0;
color: #FFF;
font-size: 20px;
background-color: rgba(0, 0, 0, 0.85);
width: 100%;
height: 100%;
padding: 0;
z-index: 2147483647;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
backface-visibility: hidden;
}
.overlay-item .vo-question {
margin: 10px 0 40px 0;
width: 80%;
text-align: center;
line-height: 1.5;
}
.vtask-choices-wrap {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: space-evenly;
width: 100%;
max-width: 1000px;
min-height: 10rem;
}
.vtask-choice-item .vtask-choice {
opacity: 0;
position: absolute;
top: 0;
left: 0;
}
.radio-tile {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
border: 2px solid #079ad9;
border-radius: 5px;
padding: 1rem;
transition: transform 300ms ease;
background: rgba(0,0,0,0.5);
z-index: 500;
cursor: pointer;
font-size: 18px;
text-align: center;
}
.vtask-btn-continue {
color: #FFFFFF!important;
border-color: #2B78C5;
border-bottom-color: #2a65a0;
text-decoration: none;
text-shadow: none;
color: #FFF;
background: #39F;
margin-top: 40px;
padding: 10px 20px;
font-family: Arial,sans-serif;
font-size: 16px;
}
/* FIX according https://stackoverflow.com/a/13388579/1066234 */
#videoplay {
position: absolute;
left: 0px;
top: 0px;
min-height: 100%;
min-width: 100%;
z-index: 9997;
}
#overlays-wrap {
position: absolute;
left: 0px;
top: 0px;
height: 100%;
width: 100%;
z-index: 9998;
}
#main_container {
float: left;
position: relative;
left:0;
top:0;
}
Interestingly, with the videojs plugin at https://github.com/brightcove/videojs-overlay the fullscreen overlays seem to work even on fullscreen. But I cannot figure out how it is doing it. – Demo: http://www.xfaktor.com/overlay/overlay_kroger.html – I have more complex HTML for my overlays and cannot use this plugin.
What is the solution for this video/videojs problem?
Probably it would be best if you can help, having the starting point of this fiddle (my recent implementation): https://jsfiddle.net/w5f7mk19/ Thanks!

The problem appears to be, that this library wraps the video in an additional div, and makes that div fullscreen - but your #overlays-wrap element is outside of that element, and I don’t think z-index is supposed to change anything about that(?).
Putting the overlay directly into #videowrapper in the source code doesn’t do the trick - the player library takes #videoplay, creates the wrapper div and puts the id on that. (It changes the id of the video element itself to #videoplay_html5_api, so no conflict in that regard.) The new div #videoplay becomes fullscreen, but #overlays-wrap still only is a sibling in the DOM, so outside of the fullscreen element.
But if you move #overlays-wrap into #videoplay after the player has initialized, it seems to work:
video = videojs('videoplay', options); // wraps video element into div#videoplay
$('#overlays-wrap').appendTo($('#videoplay')); // append #overlays-wrap to div#videoplay
https://jsfiddle.net/pw89cjqe/

Related

Need help to hover different background images in wordpress HTML code

I want exactly like this website: https://www.petzl.com/INT/en
I have displayed background video, 3 texts, by hovering on them the images are changing + links to access them.
But by hovering the text, petzl.com website have activated different images on hover, sometimes different images are appearing on hover.
Can I achieve the different images by css or need to have js or anything? Also need to have span/div elements to appear in one line.
My website link: beta.edgerope.com
Please find code below:
Below is the code, I have added as HTML shortcode in the page and in the background video is displayed
<style>
.image{
height: 800px;
width: 100%;
display: grid;
place-content:center;
justify-content:middle;
color: white;
font-size:30px;
background-color: #;
background-position: center;
background-size: cover;
}
.training{
display:inline-block;
padding-top: 50px;
padding-right: 1500px;
padding-bottom: 50px;
padding-left: 1px;
}
.image>div {
display: inline-block;
width: 100px;
}
.image>div img {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
z-index: 0;
display: inline-block;
}
.image>div span {
position: relative;
z-index: 1;
cursor: pointer;
display: inline-block;
}
.image>div span:hover+img {
opacity: 1;
display: inline-block;
}
.div{
dipslay
}
</style>
<div class="image">
<div class="services">
<span class="services" onclick="window.location=''">Services</span>
<img src="https://www.petzl.com/sfc/servlet.shepherd/version/download/0686800000D6sSCAAZ">
</div>
<div class="Training">
<span class="training" onclick="window.location='beta.edgerope.com/courses'">Training</span>
<img src="https://beta.edgerope.com/wp-content/uploads/2022/08/1-1-1536x864.jpg"> </div>
<div class="shop">
<span class="shop" onclick="window.location='beta.edgerope.com/shop'">Shop</span>
<img src="https://www.petzl.com/sfc/servlet.shepherd/version/download/0686800000D6sSCAAZ"> </div>
</div>
:
There are many ways to acomplish this, and you should be able to do this with pure css and html.
I've made an example that uses css pseudo elements in order to display the correct image when hovering the sections/links. Also changed up to use a tags instead of using onclick="window.location" as you did.
Here you can change/set the default image in the #hero selector
<style>
/* Styling for the default hero */
#hero {
height: 800px;
width: 100%;
display: flex;
color: black;
background-color: #000;
}
/* Wrapper for all the sections */
.hero-sections {
width: 100%;
height: 100%;
position: relative; /* Allows to change the z-index, and */
z-index: 1;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 2rem;
}
/* Container for the image */
.hero-image::after {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: -1; /* Allows the image to appear behind the text */
pointer-events: none; /* Prevent image to show when hovering the ::after element*/
background-image: var(
--bg-url
); /* Uses the images set by the html (css variable) */
opacity: 0; /* Hides the image when it's not active */
transition: opacity 0.5s; /* Adds a fade transition to the opacity*/
}
/* Styles when the the user hovers or has focus on the buttons/links */
.hero-image:is(:hover, :focus-within)::after {
opacity: 1; /* Change the opacity when the text is active/in hover */
}
/* Styles the buttons/links */
.hero-cta {
color: white;
text-decoration: none;
font-size: 2rem;
}
</style>
<div id="hero">
<div class="hero-sections">
<div
class="services hero-image"
style="
--bg-url: url(https://www.petzl.com/sfc/servlet.shepherd/version/download/0686800000D6sSCAAZ);
"
>
<a class="hero-cta" href="#">Services</a>
</div>
<div
class="training hero-image"
style="
--bg-url: url(https://beta.edgerope.com/wp-content/uploads/2022/08/1-1-1536x864.jpg);
"
>
<a class="hero-cta" href="beta.edgerope.com/courses">Training</a>
</div>
<div
class="shop hero-image"
style="
--bg-url: url(https://www.petzl.com/sfc/servlet.shepherd/version/download/0686800000D6sSCAAZ);
"
>
<a class="hero-cta" href="beta.edgerope.com/shop">Shop</a>
</div>
</div>
</div>
If you would like to go more advanced here I would recommend implementing some javascript handling mouseenter and mouseleave. As you said you used Wordpress you could also use the .hover() from jQuery.

How to change the position of the div after file upload?

I want to reposition my browse button when the user uploaded a file. This is the sample of how it should really look before and after uploading the file:
Before:
After:
I change the content of my button "Browse file" to "Replace File"
This is my html code.
<div id="uploadModal" class="upload-modal">
<div class="modal-content">
<h2 style="font-size: 24px;">Choose file</h2>
<p>
Choose the csv file containing the data you want to create a forecast for.
</p>
<div class="browse-file">
<div id="filename"></div>
<input type="file" id="file-upload" multiple required />
<label for="file-upload">Browse file</label>
</div>
<div class="options">
<button class="cancel"><h4>Cancel</h4></button>
<button class="proceed"><h4>Proceed</h4></button>
</div>
</div>
</div>
Here is my CSS
.upload-modal {
display: none;
position: fixed;
padding-top: 100px;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 34, 2, 0.3);
}
input[type="file"] {
position: absolute;
opacity: 0;
z-index: -1;
}
input + label {
padding: 10px 24px;
background: #D4E8CF;
border-radius: 100px;
position: static;
width: 119px;
height: 40px;
border: none;
cursor: pointer;
z-index: 1;
}
#filename{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100px;
justify-content: left;
align-items: flex-start;
}
What's happening here is that my button moves according to the length of the file so I added max-width but no luck. Thanks!
EDIT: I added css for upload-modal
I'm not sure you need to use absolute positioning for what you want.
You could set div#upload-modal or div.modal-content to position: relative;
and then position the button element with left: or right: or use float: right;
https://developer.mozilla.org/en-US/docs/Web/CSS/position
https://developer.mozilla.org/en-US/docs/Web/CSS/float
This alternate version uses CSS's Flexbox and JavaScript's Event Listeners.
It probably doesn't do precisely what you want but should come close enough that reading through the comments a few times and playing around with the code should make clear how you can get to where you want to go using just a few lines of JavaScript to grab the file name and show it on the screen.
MDN (linked above) is a great place to get more clarity about any particular front-end feature that you're interested in using. Happy coding!
// Unnamed function runs as soon as the DOM elements are ready
window.addEventListener('DOMContentLoaded', () => {
// Identifies some of the DOM elements
const
filenameSpan = document.getElementById("filename-span"),
fileInput = document.getElementById("file-input"),
chooseBtn = document.getElementById("choose-btn");
// When the input changes (when a file is chosen), calls `updateDisplay`
fileInput.addEventListener("change", updateDisplay);
// Defines `updateDisplay`
function updateDisplay(){
// Puts first fiename in span and "unhides" it
const filename = fileInput.files[0]?.name;
filenameSpan.textContent = filename || "(choose file)";
filenameSpan.classList.remove("hidden");
};
});
*{
margin: 0;
}
#container{
width: 18rem; /* "rem" unit is the base character height */
padding: 2rem;
border-radius: 1.5rem;
background-color: lightgrey;
}
#header{
margin-bottom: 2rem;
}
#chooser{
/* flex w/ space-around makes choose-btn shift right when filename appears */
display: flex;
justify-content: space-around;
margin-bottom: 4rem;
}
#options{
text-align: right;
}
#filename-span{
padding: 1rem 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 6rem;
}
button{ /* the "options" buttons */
border: none;
font-weight: bold;
color: darkgreen;
background-color: lightgrey;
}
#choose-btn{
/* Not a true "button" element -- the "label" for file-input */
padding: 1rem 1.5rem;
background-color: darkseagreen;
border-radius: 2rem;
border: none;
font-weight: bold;
}
.hidden{ /* Uses a class so all styling happens thru CSS */
display: none;
}
<div id="container">
<div id="header">
<h2>Choose file</h2>
<p> Choose the csv file containing the data you want to create a forecast for</p>
</div>
<div id="chooser">
<!-- The span and input elements are initially "hidden" via CSS -->
<span id="filename-span" class="hidden"></span>
<label id="choose-btn">
<!-- input element is inside its stylable & clickable label -->
Browse File
<input id="file-input" type="file" class="hidden" />
</label>
</div>
<div id="options">
<button id="cancel-btn">Cancel</button>
<button id="proceed-btn">Proceed</button>
</div>
</div>

Height of Element Issue

I have the following code:
.embed-responsive {
position: relative;
display: block;
height: 0;
padding: 0;
overflow: hidden;
}
.resume .resume-title {
font-size: 26px;
font-weight: 700;
margin-top: 20px;
margin-bottom: 20px;
color: #050d18;
}
.resume .resume-item {
position: relative;
text-align: center;
}
.add {
padding: 0;
}
#media all and (max-width: 500px) {
.embed-responsive {
height: auto;
}
}
<section id="resume" class="resume">
<div class="container">
<div class="section-title">
<h2>Resumè
</h2>
</div>
<div class="resume-item">
<iframe src="https://drive.google.com/file/d/1QQ3lCOVEBd551AuNOA-XA4x6s1I3AaCZ/preview" width="100%" height="1070"></iframe>
</div>
</div>
</section>
So on my end since I have the above code embedded in a website, the output looks like this:
However, when I view the website using a smaller screen, I am getting this output:
The problem is that the "template" (which is the grey part) extends to height: 1070 even on responsive mode. I want the grey part to end after the document with some margin like shown in the very first picture when you view it on a smaller device.
Expected Output:
Larger Screen
Same picture as the very first picture I sent, so no changes here really.
Smaller Screen:
The Blue Line is where the grey part should end, with some margin in between the document and grey part, as there is at the top. Any suggestions on how I can accomplish this?
I believe something like this:
made a class for the iframe, for the media query I put 140vw
why 140vw? the ratio of an A4 paper is around 1.4 (if you know its some other format... just change the ratio...) this means the height is 1.4 the width, so you can use that instead of a number as you're doing in the default settings.
.embed-responsive {
position: relative;
display: block;
height: 0;
padding: 0;
overflow: hidden;
}
.resume .resume-title {
font-size: 26px;
font-weight: 700;
margin-top: 20px;
margin-bottom: 20px;
color: #050d18;
}
.resume .resume-item {
position: relative;
text-align: center;
}
.add {
padding: 0;
}
.iframe {
height: 1070px;
}
#media all and (max-width: 500px) {
.embed-responsive {
height: auto;
}
.iframe {
height: 140vw;
}
}
<section id="resume" class="resume">
<div class="container">
<div class="section-title">
<h2>Resumè
</h2>
</div>
<div class="resume-item">
<iframe src="https://drive.google.com/file/d/1QQ3lCOVEBd551AuNOA-XA4x6s1I3AaCZ/preview" width="100%" class="iframe"></iframe>
</div>
</div>
</section>

Is there a way to jump from a section into another section with Vanilla JavaScript?

I have two sections one over the other.
What I want to do is that when I click the button, the first section display: none with a small transition and the second one appears. I need to do that with vanilla JavaScript as I'm learning it.
My goal is to be able to create a login when the password is entered, the person is moved to the second section. (this is just for Front end, nothing backend).
Here is the code below:
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Login Background */
#first{
position: absolute;
width: 100%;
height: 100vh;
background-color: #464159;
z-index: 1;
}
/* Login */
.login-container{
position: absolute;
top: 50%;
right: 50%;
transform: translate(50%, -100%);
display: flex;
align-items: center;
justify-content: center;
}
.logo{
justify-content: center;
margin-right: 20px;
}
.logo img{
width: 180px;
height: auto;
}
.user{
display: flex;
flex-direction: column;
}
.w8u{
color: white;
font-size: 15px;
margin: 0 0 10px 0;
}
.submit{
flex: 1;
margin: 30px 0 0 10px;
}
/* Menu */
#second{
position: absolute;
width: 100%;
height: 100vh;
background-color: orangered;
z-index: -1;
}
<body>
<section id="first">
<div class="login-container">
<!-- Logo User -->
<div class="logo">
<img src="w-logo.jpg" alt="User">
</div>
<!-- User Name -->
<div class="user">
<div class="w8u">
<h3>User</h3>
</div>
<div>
<input class="input" type="password" placeholder="Enter your password" required>
</div>
</div>
<!-- Submit Button -->
<button id="btn-submit" class="submit" type="submit" onclick="">GO!</button>
</section>
<section id="second">
</section>
<script src="app.js"></script>
</body>
Yes, you can change CSS of elements using JavaScript:
function login(){
document.getElementById("first").style.display="none";
document.getElementById("second").style.display="block";
}
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Login Background */
#first{
position: absolute;
width: 100%;
height: 100vh;
background-color: #464159;
z-index: 1;
}
/* Login */
.login-container{
position: absolute;
top: 50%;
right: 50%;
transform: translate(50%, -100%);
display: flex;
align-items: center;
justify-content: center;
}
.logo{
justify-content: center;
margin-right: 20px;
}
.logo img{
width: 180px;
height: auto;
}
.user{
display: flex;
flex-direction: column;
}
.w8u{
color: white;
font-size: 15px;
margin: 0 0 10px 0;
}
.submit{
flex: 1;
margin: 30px 0 0 10px;
}
/* Menu */
#second{
position: absolute;
width: 100%;
height: 100vh;
background-color: orangered;
z-index: -1;
}
<body>
<section id="first">
<div class="login-container">
<!-- Logo User -->
<div class="logo">
<img src="w-logo.jpg" alt="User">
</div>
<!-- User Name -->
<div class="user">
<div class="w8u">
<h3>User</h3>
</div>
<div>
<input class="input" type="password" placeholder="Enter your password" required>
</div>
</div>
<!-- Submit Button -->
<button id="btn-submit" class="submit" type="submit" onclick="login()">GO!</button>
</section>
<section id="second">
Section 2
</section>
<script>
</script>
</body>
Short Answer:
You can solve your issue by using a common pattern of styling transitions and toggling classes in JavaScript.
/* Get Screen Container */
let context = document.querySelector("main.screen-container");
/* Helper Methods */
// Utility
const ele = context.querySelector.bind(context),
eles = context.querySelectorAll.bind(context);
// Action
const showScreen = inactiveScreen => {
const screens = eles(".screen");
screens.forEach(screen => screen.classList.remove("active-screen"));
inactiveScreen.classList.add("active-screen");
}
// Elements
const login_button = ele("#loginBtn"),
logout_button = ele("#logoutBtn"),
login_screen = ele("#login"),
loggedIn_screen = ele("#loggedIn");
// Add Event Listeners and Handlers
login_button.addEventListener("click", () => showScreen(loggedIn_screen));
logout_button.addEventListener("click", () => showScreen(login_screen));
.full-width-full-height {
width: 100%;
height: 100%;
}
.no-overflow {
overflow: hidden;
}
.inputs-container {
display: flex;
flex-direction: column;
justify-content: center;
height: 200px;
padding: 5px;
border: 5px black solid;
}
.inputs-container.inputs {
padding: 10px;
}
.screen#login {
display: flex;
justify-content: center;
}
.screen#loggedIn {
background: rgba(0,0,0,.5);
border: 5px solid rgba(0,0,0,.3);
text-align: center;
}
highlight {
color: rgb(0,100,0);
text-shadow: 3px 3px 10px rgb(0,200,0);
}
.screen-container {
height: 100%;
width: 100%;
overflow: hidden;
padding: 0px;
margin: 0px;
}
main section {
position: absolute;
height: 0px;
width: 0px;
opacity: 0;
transition: all .3s ease-in-out;
}
main section.active-screen {
height: 100%;
width: 100%;
opacity: 1;
}
<body class="full-width-full-height no-overflow">
<main class="screen-container full-width-full-height">
<section id="login" class="screen active-screen">
<div class="inputs-container">
<div class="inputs"><label>Username:</label><input type="text" id="username" placeholder="admin" /></div>
<div class="inputs"><label>Password:</label><input type="password" id="password" /></div>
<button id="loginBtn">login</button>
</div>
</section>
<section id="loggedIn" class="screen">
<h3>User Successfully <highlight>Logged In</highlight></h3>
<button id="logoutBtn">logout</button>
</section>
</main>
</body>
Explanation of Answer:
In your question you're asking for help in the following:
Using Sections as Different Screens in an Application
Change Screens on an Event such as click
Transition between Screens when the Screen Changes
Something like this isn't an atypical need and, in fact, just looking at the above you can see the resemblance between what you're looking for and common things like a carousel or tab navigation.
Since this is the case there is a pretty common pattern when designing markup based around these types of requirements and this pattern is used in frameworks like BootStrap, DataTables, JQuery, etc.
The Mark-Up Pattern:
Create a Container
Provide a class to define this type of container ( screen-container )
Create Visual Elements
In your case Section Elements dubbed Screens
Provide a class to define these specific elements
In your case something like screen
You will likely also want to provide an ID for each of these Visual Elements based on their Content.
In your case something like login and loggedIn
Create a class that will serve as the active Visual Element
In your case something like active-screen
Incorporating the above you end up with a basic outline:
<main class="screen-container">
<section id="login" class="screen active-screen"></section>
<section id="loggedIn" class="screen"></section>
</main>
Example:
html, body, main, .screen-container {
height: 100%;
width: 100%;
}
.screen-container
.screen {
padding: 3px;
background: rgba(24,24,24, .3);
border: 3px solid black;
width: 100px;
height: 100px;
}
.screen-container
.screen.active-screen {
border-color: green;
}
<main class="screen-container">
<section id="login" class="screen active-screen">login</section>
<section id="loggedIn" class="screen">logged in</section>
</main>
Styling:
In your initial question you say that you want to use the display property to hide and show your screens, however, you also state that you would like to have the screens transition from one to another.
Transitioning is definitely possible through the aptly named CSS transition property ( More info on MDN ).
The problem is that the display property is not able to be animated. If an element is configured to display: none; the page is immediately repainted with that element removed.
This means that you need to use a different property, and we typically would use opacity or visibility. Here are the differences between these three:
display: none;
immediately collapses the element
removes the element from view.
There's no transition allowed.
visibility: hidden;
Does not collapse the element
The space it occupied is blank.
removes the element from view
Transitions are allowed
The element will still pop out of sight.
opacity: 0;
Does not collapse the element
The space it occupied is blank.
removes the element from view
Transitions are allowed.
The element will fade until it is not visible.
Here is an example of the different way these properties affect the layout of the page:
const context = document.querySelector("#examples");
const ele = context.querySelector.bind(context),
hide = section => section.classList.toggle("hide"),
onClickHide = (btn, section) => btn.addEventListener("click", () => hide(section));
opacity = ele(".opacity"),
opacity_button = ele("#oBtn"),
visibility = ele(".visibility"),
visibility_button = ele("#vBtn"),
display = ele(".display"),
display_button = ele("#dBtn"),
toggle_button = ele("#tBtn");
onClickHide(opacity_button, opacity);
onClickHide(visibility_button, visibility);
onClickHide(display_button, display);
toggle_button
.addEventListener("click", function() {
hide(opacity);
hide(visibility);
hide(display);
});
html,
body,
#examples {
width: 100%;
height: 100%;
box-sizing: content-box;
margin: 0px;
padding: 0px;
}
#examples section {
display: flex;
flex-direction: column;
width: 100px;
height: 100px;
border: 5px solid black;
margin: 5px;
transition: all .5s ease-in-out;
}
#examples section.hide {
border-radius: 100px;
}
#examples section.opacity {
background-color: blue;
color: white;
}
#examples section.opacity.hide {
opacity: 0;
}
#examples section.visibility {
background-color: purple;
color: white;
}
#examples section.visibility.hide {
visibility: hidden;
}
#examples section.display {
display: block;
background-color: red;
color: white;
}
#examples section.display.hide {
color: black;
display: none;
}
<main id="examples">
<section class="opacity">opacity <button id="oBtn">hide</button></section>
<hr />
<section class="visibility">visibility <button id="vBtn">hide</button></section>
<hr />
<section class="display">display <button id="dBtn">hide</button></section>
<hr/>
<button id="tBtn">Toggle All</button>
</main>
Note: In the above there are actually two properties transitioning - opacity, visibility, or display - and border-radius. You should notice firstly how in the display example the border-radius change isn't seen at all, and secondly how the display example is the only one that collapses the element so that it no longer takes up space.
Applying Transitions:
By combining opacity: 0; with height: 0px; width: 0px; we can remove the element visually from the page while also removing any impact it has on other elements - meaning that it won't take up space and is transitionable.
setInterval(function() {
const screens = [
document.querySelector(".screen.active-screen"),
document.querySelector(".screen:not(.active-screen)")
];
screens[0].classList.toggle("active-screen");
screens[0].ontransitionend = () => {
screens[1].classList.toggle("active-screen");
screens[0].ontransitionend = undefined;
}
}, 1000)
html,
body,
main,
.screen-container {
height: 100%;
width: 100%;
}
.screen-container .screen {
transition: all .3s ease-in-out;
opacity: 0;
height: 0px;
width: 0px;
}
.screen-container .screen.active-screen {
background: rgba(24, 24, 24, .3);
border: 3px solid black;
padding: 3px;
border-color: green;
width: 100px;
height: 100px;
opacity: 1;
}
<main class="screen-container">
<section id="login" class="screen active-screen">login</section>
<section id="loggedIn" class="screen">logged in</section>
</main>
JavaScript
The final piece of the puzzle is the JavaScript mechanics of the Screens.
Any Programmer wants to make the switch as easy as possible, and this is done typically by providing a function that allows for quick reassignment of the class active-screen by removing it from the current active screen and applying it to the desired visual element.
One thing to take into account is that you want your queries for elements to be as specific as possible. Meaning that instead of document.querySelector you want to provide the smallest context of where to find your Visual Elements. a.e.
/* Get Screen Container */
let context = document.querySelector("main.screen-container");
/* Helper Methods */
// Utility
const ele = context.querySelector.bind(context),
eles = context.querySelectorAll.bind(context);
This prevents code collision where other code in your Application's JavaScript, Styling, or Mark-Up may utilize a screen or active-screen class that isn't relevant to what you're doing here.
Note: This is actually a problem in BootStrap currently. It searches for the active class in it's Tab architecture. This is such a generic class name that other libraries utilize it and it can cause a giant headache to get things to work properly. Writing explicit patching because you didn't think through your design fully is something I'd just as soon spare you from, so try to keep interactivity with other code in mind.
Lastly we write our function ( showScreen ) that allow for quick, easy switching between screens:
// Action
const showScreen = inactiveScreen => {
const screens = eles(".screen");
screens.forEach(screen => screen.classList.remove("active-screen"));
inactiveScreen.classList.add("active-screen");
}
And believe it or not, that's pretty much it!
All that's left to do is apply this functionality to your button click events and it works just as it should:
Result:
/* Get Screen Container */
let context = document.querySelector("main.screen-container");
/* Helper Methods */
// Utility
const ele = context.querySelector.bind(context),
eles = context.querySelectorAll.bind(context);
// Action
const showScreen = inactiveScreen => {
const screens = eles(".screen");
screens.forEach(screen => screen.classList.remove("active-screen"));
inactiveScreen.classList.add("active-screen");
}
// Elements
const login_button = ele("#loginBtn"),
logout_button = ele("#logoutBtn"),
login_screen = ele("#login"),
loggedIn_screen = ele("#loggedIn");
// Add Event Listeners and Handlers
login_button.addEventListener("click", () => showScreen(loggedIn_screen));
logout_button.addEventListener("click", () => showScreen(login_screen));
.full-width-full-height {
width: 100%;
height: 100%;
}
.no-overflow {
overflow: hidden;
}
.inputs-container {
display: flex;
flex-direction: column;
justify-content: center;
height: 200px;
padding: 5px;
border: 5px black solid;
}
.inputs-container.inputs {
padding: 10px;
}
.screen#login {
display: flex;
justify-content: center;
}
.screen#loggedIn {
background: rgba(0,0,0,.5);
border: 5px solid rgba(0,0,0,.3);
text-align: center;
}
highlight {
color: rgb(0,100,0);
text-shadow: 3px 3px 10px rgb(0,200,0);
}
.screen-container {
height: 100%;
width: 100%;
overflow: hidden;
padding: 0px;
margin: 0px;
}
main section {
position: absolute;
height: 0px;
width: 0px;
opacity: 0;
transition: all .3s ease-in-out;
}
main section.active-screen {
height: 100%;
width: 100%;
opacity: 1;
}
<body class="full-width-full-height no-overflow">
<main class="screen-container full-width-full-height">
<section id="login" class="screen active-screen">
<div class="inputs-container">
<div class="inputs"><label>Username:</label><input type="text" id="username" placeholder="admin" /></div>
<div class="inputs"><label>Password:</label><input type="password" id="password" /></div>
<button id="loginBtn">login</button>
</div>
</section>
<section id="loggedIn" class="screen">
<h3>User Successfully <highlight>Logged In</highlight></h3>
<button id="logoutBtn">logout</button>
</section>
</main>
</body>
Conclusion:
I hope this helps and gives you some insight into how this pattern is used! It's not a difficult thing to learn, but it's incredibly useful!
Good luck and Happy Coding!

Ability to flip div boxes, changing their size, and interacting with the content

I'm trying to create a design with small clickable div boxes, that once clicked they flip by 180° and show content. Content which you can interact with: like clicking links, copy text or change the content with the use of more buttons.
I've managed to accomplish this, but my question follows: Is there a better way for this?
Found this website of a basic example
But being CSS based the content on the other side isn't interactable.
This is the code:
HTML
<div id="saos">
<div id="pg1" style="display:none;">
<blockquote>Page1</blockquote><br>
Yay content.
</div>
<div id="pg2" style="display:none;">
<blockquote>Page2</blockquote><br>
More content.
</div>
<div class="x" style="display:none;" onclick="closePage()">
<p>X</p>
</div>
<div id="2" class="an2 start startbak" onclick="openPage()">
<p class="sp">Click!</p>
</div>
<div id="cont" style="display:none;">
<p class="sp">Click!</p>
</div>
</div>
CSS
.write {
position: absolute;
width: 100px;
height: 50px;
background: #0055ff;
-webkit-transition: all 1.5s cubic-bezier(.08, 1, .08, 1);
left: 10px;
text-align: center;
font-family: Verdana;
}
.write:hover {
-webkit-transform: perspective(600px)scale(1.2);
-moz-transform: perspective(600px)scale(1.2);
}
.write p {
color: #002164;
text-align: center;
margin-top: 10px;
font-size: 22px;
}
.an {
-webkit-transition: all 1.5s cubic-bezier(.08, 1, .08, 1);
}
.an2 {
-webkit-transition: all .5s ease;
}
.page {
background-color: rgba(17, 17, 17, .8);
position: absolute;
left: 120px;
border: 2px solid #252525;
height: 330px;
width: 530px;
overflow: auto;
font-size: 14px;
color: #818181;
}
.start {
text-align: center;
font-family: Verdana;
position: absolute;
top: 150px;
left: 290px;
height: 120px;
width: 120px;
-webkit-transform: perspective(600px)rotateY(180deg)translateZ(-10px);
-moz-transform: perspective(600px)rotateY(180deg);
}
.start:hover {
background-color: #0055ff;
cursor: pointer;
}
.startbak {
background-color: #0036a3;
}
.mainbak {
background: #252525;
}
.sp {
color: #002164;
margin-top: 43px;
font-size: 30px;
-webkit-transform: rotateY(180deg)rotateZ(-45deg)translateZ(-10px);
-moz-transform: rotateY(180deg)rotateZ(-45deg);
}
.frame {
top: 0px;
left: 0px;
position: absolute;
width: 751px;
height: 452px;
-webkit-transform: perspective(600px)rotateY(0deg);
-moz-transform: perspective(600px)rotateY(0deg);
}
.x {
position: absolute;
left: 700px;
height: 18px;
width: 45px;
background-color: #c75050;
color: #fff;
display: table;
text-align: center;
font-size: 10px;
font-family: Verdana;
z-index: 2;
}
.x:hover {
background-color: #e04343;
cursor: default;
}
.x:active {
background-color: #993d3d;
}
.x p {
display: table-cell;
vertical-align: middle;
}
JavaScript
var htmlString = '<div class="f an write" style="top: 10px;" name="Home" onClick="openTab(\'pg1\',\'0\')"><p>Home</p></div>\n'
htmlString += '<div class="f an write" style="top: 65px;" name="About" onClick="openTab(\'pg2\',\'1\')"><p>About</p></div>\n'
function openTab(id, n){
for (var i=0;i<write.length;i++){
write[i].className = 'f an write';
write[i].style.top = i*55+10+'px';
name = write[i].getAttribute('name');
write[i].innerHTML = '<p>'+name+'</p>';
}
write[n].className = 'f an page';
write[n].style.top = '10px';
write[n].innerHTML= '<div class="ins">'+document.getElementById(id).innerHTML+'</div>';
}
var id2 = document.getElementById('2'),
x = document.getElementsByClassName('x')[0];
function openPage(){
id2.className = 'an2 frame mainbak';
setTimeout(function() {
id2.className = 'an2 frame mainbak'
id2.setAttribute('onclick','')
document.getElementById('2').innerHTML=htmlString
}, 150);
setTimeout(function() {
x.style.display='';
}, 600);
}
function closePage(){
id2.className = 'an2 start mainbak';
setTimeout(function() {
id2.className = 'an2 start startbak'
id2.setAttribute('onclick','openPage()')
document.getElementById('2').innerHTML=document.getElementById('cont2').innerHTML
}, 150);
x.style.display='none';
}
Also made a JSFiddle but it doesn't seem to work..
While on my browser does.
It should be possible to do this with only a couple of lines of Javascript. Rich Bradshaw's example that you posted was an excellent starting point.
Rather than starting the flip on hover (via css selectors) I added a couple of lines of Javascript - actually jQuery, but plain JS would work - to add the relevant class on click. It works really nicely...
See jsFiddle Demo
I also managed to get the back face clickable (as in that demo) so it should meet all of your needs.
By that method the HTML is reduced to:
<div id="f1_container">
<div id="f1_card" class="shadow">
<div class="front face">
<img src="http://lorempixel.com/450/281/" />
</div>
<div class="back face center">
<p>This is nice for exposing more information about an image.</p>
<p>Any content can go here.</p>
<p>Including interactive HTML like
links</p>
</div>
</div>
</div>
And the Javascript is just:
$('#f1_container').click(function() {
$('#f1_container').addClass('clicked');
});

Categories