I'm trying to animate a div with a translate3D, it's working perfectly everywhere except on webkit-mobile where the property is well interpreted but the div goes directly to the endpoint.
I tried to use the webkit transition without any difference and the debugger is telling me that everything should work.
Please tell me there is something I don't understand (it's driving me crazy)
JS
function setTransform(x, y, deg, duration) {
current.style.transform = `translate3d(${x}px, ${y}px, 0) rotate(${deg}deg)`
likeText.style.opacity = Math.abs((x / innerWidth * 2.1))
likeText.className = `is-like ${x > 0 ? 'like' : 'nope'}`
if (duration) {
current.style.transition = `transform ${duration}ms`
current.style.webkitTransition = `transform ${duration}ms`
// debugger;
}
}
CSS of the "current" element
.card {
position: absolute;
display: flex;
align-items: flex-start;
justify-content: space-between;
width: 100%;
height: 100%;
color: #f1f1f1;
border-radius: 10px;
user-select: none;
cursor: pointer;
overflow-y: scroll;
touch-action: none;
flex-direction: column;
}
Related
I'm trying to have a div centered in the screen. This div should have a specific width and height when it fits in the available window space, but it should shrink to fit when the available window space is not enough, but also, maintaining its original aspect ratio.
I've been looking at lots of examples that work for a decreasing width, but none that work for both width and height changes in the window size.
Here's my current CSS:
* {
border: 0;
padding: 0;
margin: 0;
}
.stage_wrapper {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
width: 960px;
height: 540px;
max-width: 90%;
max-height: 90%;
display: flex;
justify-content: center;
align-items: center;
background: chocolate;
object-fit: contain; /* I know this is for images, it's an example of what I'm looking for */
}
And, my current HTML:
<div class="stage_wrapper">
<div class="stage">
<p>Some text</p>
</div>
</div>
This is showing a centered div that has a fixed width of 960px and a fixed height of 540px. It should never be bigger than that.
Then, if I change the size of my window to have a smaller width or height than that, the div element is successfuly shrinking - except it is not maintaining the original aspect ratio, and that is what I'm looking for. I want it to respond to changes in both width and height.
Is this possible at all?
The aspect-ratio ref property has a good support now so you can use the below:
body {
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
--r: 960 / 540;
aspect-ratio: var(--r);
width:min(90%, min(960px, 90vh*(var(--r))));
display: flex;
justify-content: center;
align-items: center;
background:
/* this gradient is a proof that the ratio is maintained since the angle is fixed */
linear-gradient(30deg,red 50%,transparent 50%),
chocolate;
}
<div class="stage">
<p>Some text</p>
</div>
Old answer
Here is an idea using viewport unit and clamp(). It's a kind of if else to test if the width of the screen is bigger or smaller than the height (considering the ratio) and based on the result we do the calculation.
In the code below with have two variables cv and ch and only one of them will be equal to 1
If it's cv then the width is bigger so we set the height to cv and the width will be based on that height so logically cv/ratio
If it's ch then the height is bigger so we set the width to cv and the height will be based on that width so logically ch/ratio
In the clamp() I am using 1vh/1vw that I multiple by 90 which is equivalent to your 90% to have 90vh/90vw
body {
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
--r: calc(960 / 540);
--cv: clamp(0px,(100vw - 100vh*var(--r))*10000,1vh);
--ch: clamp(0px,(100vh*var(--r) - 100vw)*10000,1vw);
height: calc((var(--cv) + var(--ch)/var(--r)) * 90 );
width: calc((var(--ch) + var(--cv)*var(--r)) * 90 );
max-width: 960px;
max-height: 540px; /* OR calc(960px/var(--r)) */
display: flex;
justify-content: center;
align-items: center;
background:
/* this gradient is a proof that the ratio is maintained since the angle is fixed */
linear-gradient(30deg,red 50%,transparent 50%),
chocolate;
}
<div class="stage">
<p>Some text</p>
</div>
In theory the clamp can be simplified to:
--cv: clamp(0px,(1vw - 1vh*var(--r)),1vh);
--ch: clamp(0px,(1vh*var(--r) - 1vw),1vw);
But to avoid any rounding issue and to not fall into values like 0.x I consider a big value to make sure it will always be clamped to 1 if positive
UPDATE
It seems there is a bug with Firefox so here is another version of the same code:
body {
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
--r: calc(960 / 540);
--cv: clamp(0px,(100vw - 100vh*var(--r))*100,90vh);
--ch: clamp(0px,(100vh*var(--r) - 100vw)*100,90vw);
height: calc((var(--cv) + var(--ch)/var(--r)) );
width: calc((var(--ch) + var(--cv)*var(--r)) );
max-width: 960px;
max-height: 540px; /* OR calc(960px/var(--r)) */
display: flex;
justify-content: center;
align-items: center;
background:
/* this gradient is a proof that the ratio is maintained since the angle is fixed */
linear-gradient(30deg,red 50%,transparent 50%),
chocolate;
}
<div class="stage">
<p>Some text</p>
</div>
Any solution using vw & vh assumes your container is the viewport. But what if you need an element that letterboxes to fit any container?
In other words, you want the behavior of object-fit: contain for an element that's not an <img> or <video>.
You need a container that centers both vertically and horizontally:
#container {
display: flex;
align-items: center;
justify-content: center;
}
and a contained object with fixed aspect-ratio that stretches either its width or height to 100%:
#object {
aspect-ratio: 16/9;
overflow: hidden;
[dimension]: 100%;
}
where [dimension] is width if the container is tall, and height otherwise.
If you don't know ahead of time whether it's going to be tall or not, a little javascript is needed to check for tallness and decide which dimension to stretch.
function update() {
const isTall = container.clientWidth / container.clientHeight < aspectRatio;
object.style.width = isTall ? '100%' : 'auto';
object.style.height = isTall ? 'auto' : '100%';
}
new ResizeObserver(update).observe(container);
I don't think this dimension switching can be accomplished in pure CSS without javascript.
Here's a demo.
You can set your height and width like:
height: 80vw;
width: 80vw;
Then, you can set the max height and width like:
max-height: 100vh;
max-width: 100vh;
Or if you have other things like headers in the way then:
max-height: calc(100vh - 32px);
max-width: calc(100vh - 32px);
The 32px is how many pixels(or other measurements) it takes up
Use this CSS maybe:
.stage_wrapper {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
width: 50vw;
height: 40vw;
max-width: 90%;
max-height: 90%;
display: flex;
justify-content: center;
align-items: center;
background: chocolate;
object-fit: contain; /* I know this is for images, it's an example of what I'm looking for */
}
You can adjust the code if you want to to be bigger or smaller, but this will let your div have a fixed aspect ratio.
On the website down below, when I close the side menu in mobile, I can see the body of the menu close faster than the texts and search icon. Why did this happen? Why they don't close together?
I used the Divi plugin on WordPress but I think there isn't any conflict.
It opens and closes smoothly and well on the desktop.
https://wordpress-602494-1949747.cloudwaysapps.com/
<script>
let isMenuOpen = false;
const menuHandler = document.querySelector('.menu_left_handler');
const menuTitle = document.querySelector('.menu_left_title');
const menuRight = document.querySelector('.menu_right');
menuHandler.addEventListener('click', () => {
isMenuOpen ? menuRight.classList.remove('menu_right__open') : menuRight.classList.add('menu_right__open');
isMenuOpen = !isMenuOpen;
menuHandler.innerText === '☰' ? (menuHandler.innerText = '✕') : (menuHandler.innerText = '☰');
menuTitle.innerText === 'MENY' ? (menuTitle.innerText = 'STÄNG') : (menuTitle.innerText = 'MENY');
});
let x = window.matchMedia("(max-width: 768px)")
function mediaQ(x) {
if (x.matches) {
menuHandler.addEventListener('click', () => {
let mobileMenu = document.getElementById("menuId")
mobileMenu.classList.toggle("menu_right__open");
});
}
}
#menuId {
background: #171717;
border-radius: 0 1rem 1rem 0;
padding: 1rem;
display: inline-flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: flex-start;
align-content: stretch;
color: #fff;
font-family: 'museo-sans', sans-serif !important;
height: 30rem;
}
.menu {
height: 25rem;
}
#menu a {
color: #fff;
}
.menu_right {
max-width: 0;
overflow: hidden;
transition: max-width 0.3s;
}
.menu_right__open {
max-width: 100rem !important;
height: 25rem;
transition: max-width 2s;
}
.menu_right ul {
list-style: none;
width: 20rem;
padding-top: 5rem;
padding-left: 2rem;
line-height: 35px;
}
.menu_right ul a {
display: block;
text-decoration: none;
margin: 1rem 0;
font-size: 20px;
}
.menu_right ul a:hover {
color: #F7B660 ;
}
.menu_left {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
align-content: center;
font-size: 20px;
}
.menu_left_title {
font-family: 'museo-sans', sans-serif !important;
font-size: 20px;
writing-mode: tb-rl;
transform: rotate(-180deg);
margin-top: 1rem;
padding: 0.3rem;
}
.menu_left_handler {
padding: 0.5rem;
cursor: pointer;
font-size: 35px;
}
#media screen and (max-width: 768px) {
#menuId {
height: 5rem;
}
.menu {
height: 5rem;
}
.menu_left_title {
display: none;
}
.menu_right__open {
height: 26rem !important;
overflow-y: none !important;
border-radius: 2px;
transition: max-width 4s;
}
.menu_right {
transition: max-width 0.3s;
}
.menu_right ul a {
}
.menu_left_handler {
padding: 0.5rem;
cursor: pointer;
font-size: 18px;
}
}
<body>
<div id="menuId" class="menu">
<div class="menu_left">
<div class="menu_left_handler">☰</div>
<div class="menu_left_title">MENY</div>
</div>
<div class="menu_right">
<div class="et_pb_with_border et_pb_module et_pb_search et_pb_search_0_tb_header et_pb_text_align_left et_pb_bg_layout_light et_pb_hide_search_button">
<form role="search" method="get" class="et_pb_searchform" action="https://wordpress-602494-1949747.cloudwaysapps.com/">
<div>
<label class="screen-reader-text" for="s">Search for:</label>
<input type="text" name="s" placeholder="" class="et_pb_s">
<input type="hidden" name="et_pb_searchform_submit" value="et_search_proccess">
<input type="hidden" name="et_pb_include_posts" value="yes">
<input type="hidden" name="et_pb_include_pages" value="yes">
<input type="submit" value="Search" class="et_pb_searchsubmit" style="">
</div>
</form>
</div>
<nav>
<ul><strong>
<li>Robotlösningar</li>
<li>Made by Andon</li>
<li>Eftermarknad</li>
<li>Kontakt</li>
<li>Om Andon Robotics</li>
</strong>
</ul>
</nav>
</div>
</div>
</body>
This will because you are not transitioning the height when you are closing the div causing it to snap closed, as you are just transitioning the max-width this will cause the width the issue you are facing.
Firstly i would add your transition to your div with the ID of menuID rather than the actual class you are adding on click. Play around with it but you need to transition the height as well as the width otherwise the height is just going to snap. Maybe look into doing your transitions something like this. The example im giving you isnt a 100% fix but it is going to point you in the direction you need to go in order to understand your issue
transition:max-width 0.4s, height 0.4s;
as #Stevo stated below this, that is mainly the problem. However, if you intend to animate the whole menu altogether as its expanding smoothly and consistently from one point of origin I'd suggest you either use transform:scale(); to animate its growth, or you translate the whole panel from top-left to bottom-right fading the content as it comes into the viewport.
The problem with this:
transition:max-width 0.4s, height 0.4s;
Is that you are only stating the time or the animation to run but your width and height are different. Therefore it will not expand consistently.
Also, do not try to make it expand synchronously by editing the time values because it is 1) a terrible approach, and 2) all works fine until you add something to the menu and the height changes.
I use the Divi theme on my Wordpress site and I am using their theme builder to design all of my category pages. I found this template which I like the look of - https://divisoup.com/css-grid-blog-layout/
This includes adding the below JavaScript code to do some of the design as well as the following CSS too.
<script>
//CSS Grid Blog Layout by Divi Soup
(function ($) {
$(document).ready(function () {
//Wrap first grid elements in containers
$(".ds-grid-blog-1 .et_pb_post").each(function () {
$(this).find(".entry-featured-image-url").wrapAll('<div class="ds-grid-blog-image"></div>');
$(this).find(".entry-title, .post-meta, .post-content").wrapAll('<div class="ds-grid-blog-content"></div>');
});
});
})(jQuery);
(function ($) {
$(document).ready(function () {
$(document).bind('ready ajaxComplete', function () {
//Wrap second grid elements in containers
$(".ds-grid-blog-2 .et_pb_post").each(function () {
$(this).find(".entry-featured-image-url").wrapAll('<div class="ds-grid-blog-image"></div>');
$(this).find(".entry-title, .post-meta, .post-content").wrapAll('<div class="ds-grid-blog-content"></div>');
});
//Move elements around
$(".et_pb_post").each(function () {
$(".post-meta", this).insertBefore($(".entry-title", this));
});
//Add button class to read more link
$(".et_pb_post a.more-link").addClass("et_pb_button");
//Replace pipes and remove commas from the meta
$(".et_pb_post").html(function () {
return $(this).html().replace(/\|/g, '/').replace(/,/g, '');
});
});
});
})(jQuery);
//End CSS Grid Blog Layout by Divi Soup
</script>
/*-----------------------------------------------*/
/*-------CSS Grid Blog Layout by Divi Soup-------*/
/*-----------------------------------------------*/
/*Blog layout settings, adjust these values only*/
:root {
--ds-white: #ffffff; /*The background colour for the post content and text colour for the second and third post content*/
--ds-grid-2-item: 250px; /*Minimum column width for second grid, decrease this value for more columns*/
--ds-grid-gap: 30px; /*The gap between posts*/
--ds-title-background: rgba(0, 0, 0, .5); /*The background colour of the titles on the second and third posts*/
}
/******************************************************/
/*You should not need to edit anything below this line*/
/******************************************************/
/*Set posts to flex and remove post margin*/
.ds-grid-blog .et_pb_post {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
margin-bottom: 0;
}
/*Set flex direction for second grid*/
.ds-grid-blog-2 .et_pb_post {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
/*Set post content to flex*/
.ds-grid-blog-content {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
background: var(--ds-white);
}
/*Remove image margin and resize for responsiveness*/
.ds-grid-blog .entry-featured-image-url {
margin-bottom: 0;
height: 100%;
width: auto;
}
.ds-grid-blog .et_pb_post a img {
height: 100%;
-o-object-fit: cover;
object-fit: cover;
}
/*Reset the read more link display*/
.ds-grid-blog a.more-link {
display: initial;
}
/*Add margin to excerpt*/
.ds-grid-blog .post-content p {
margin-bottom: 20px;
}
/*Pagination placement*/
.ds-grid-blog .pagination {
grid-column: 1/-1;
}
/*Set the grid for the first 3 posts*/
.ds-grid-blog-1 .et_pb_ajax_pagination_container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: var(--ds-grid-gap);
}
/*Set the grid for the remaining posts*/
.ds-grid-blog-2 .et_pb_ajax_pagination_container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--ds-grid-2-item), 1fr));
grid-gap: var(--ds-grid-gap);
}
/*First grid first post placement*/
.ds-grid-blog-1 .et_pb_post:first-child {
grid-column: 1 / -1;
}
/*First grid second post placement*/
.ds-grid-blog-1 .et_pb_post:nth-child(2) {
grid-column: 1 / 2;
}
/*First grid third post placement*/
.ds-grid-blog-1 .et_pb_post:nth-child(3) {
grid-column: 2 / 3;
}
/*First post content*/
.ds-grid-blog-1 .et_pb_post:first-child .ds-grid-blog-content {
width: 60%;
padding: 30px;
display: -webkit-box;
display: -ms-flexbox;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
}
/*Position and colour for second & third posts*/
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .ds-grid-blog-content {
background: var(--ds-title-background);
position: absolute;
left: 0;
right: 0;
bottom: 0;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
padding: 10px;
text-align: center;
}
/*Text colour for second & third posts*/
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .entry-title,
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .post-meta,
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .post-meta a {
color: var(--ds-white) !important;
}
/*Font size for second & third posts*/
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .entry-title {
font-size: 150% !important;
}
/*Hide excerpt for second & third posts and second grid posts*/
.ds-grid-blog-1 .et_pb_post:nth-child(n+2) .post-content,
.ds-grid-blog-2 .et_pb_post .post-content p {
display: none;
}
/*Remaining posts display*/
.ds-grid-blog-2 .et_pb_post .ds-grid-blog-content {
padding: 30px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
height: 100%;
}
/*Set margin for remaining posts*/
.ds-grid-blog-2 .et_pb_post .entry-title {
margin-bottom: 30px;
}
/*Keep read more link at bottom*/
.ds-grid-blog-2 .et_pb_post .post-content {
margin-top: auto;
}
/*Adjust for mobile*/
#media all and (max-width:980px) {
.ds-grid-blog-1 .et_pb_post:first-child {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.ds-grid-blog-1 .et_pb_post:first-child .ds-grid-blog-content {
width: 100%;
}
.ds-grid-blog-1 .et_pb_post {
grid-column: 1 / -1 !important;
}
}
/*-----------------------------------------------*/
/*-----End CSS Grid Blog Layout by Divi Soup-----*/
/*-----------------------------------------------*/
.more-link.et_pb_button {
text-transform: capitalize;
color: #3984BC;
}
This is the page in question - https://travellingpair.co.uk/destinations/europe/
I'm unsure as to what is causing the errors or what they mean, but it is stopping other things from loading on the page, such as the background image behind the page header, but the actual blog design is as expected.
The errors are:
UPDATE: Figured out that the issue was being caused by this piece of code:
$(".et_pb_post").html(function () {
return $(this).html().replace(/\|/g, '/').replace(/,/g, '');
});
It was removing the commas from within the srcset attribute as well and therefore making it invalid. It should have only been removing the commas and replacing the | with / in the post meta, but looks like it was doing it with the images as well. If anyone has any ideas on that bit it would be appreciated.
Okay so I did some digging and this was being caused by the following piece of code in the JS code:
$(".et_pb_post").html(function () {
return $(this).html().replace(/\|/g, '/').replace(/,/g, '');
});
This was meant to replace all pipes with slashes as well as removing the commas from the post-meta, but looks like the person who created the layout and code had set this to apply within the ".et_pb_post" class rather than ".post-meta" to just have it remove from the meta. Instead it was doing this in the whole post and that included taking the commas out of the "srcset" attribute meaning it was invalid.
On a desktop the div with class="content" will be visible when hovering on the div with class="button". There is also a callback so it automatically fades out when hovering somewhere else.
But, this is not working on a mobile device because it is not possible to hover. I tried different solutions like adding other pseudo-classes (:active, :focus) and tried some JavaScript / jQuery. I also found this question How to simulate hover effect on touch devices?. I think JS is the best way to solve this problem but I am not used to work with that.
Here is my HTML code:
<div class="home">
<div class="button">
<div class="content"></div>
</div>
</div>
CSS:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.home {
display: flex;
justify-content: center;
align-items: center;
background-color: #3d2885;
width: 100vw;
height: 100vh;
}
.button {
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
width: 50vmin;
height: 50vmin;
background-color: white;
border-radius: 50%;
}
.content {
width: 0vmin;
height: 0vmin;
background-color: lightgreen;
-webkit-transition: 0.5s ease-in-out;
transition: 0.5s ease-in-out;
}
.button:hover .content {
width: 25vmin;
height: 25vmin;
border-radius: 15%;
}
And I tried some jQuery:
$('.button').bind('touchstart', function() {
$(this).addClass('content');
});
$('.button').bind('touchend', function() {
$(this).removeClass('content');
});
Can anyone tell me how I can implement jQuery (or something else) so that a click event on a mobile device has the same effect as a hover effect on a desktop?
In this case I mean that the div with class="content" has a transition effect (growing) on clicking and a transition effect (shrinking) on clicking somewhere else.
Codepen example: https://codepen.io/elinehendrikse/pen/JJVRLm?editors=0110
I'm using bootstrap and have used the vh code to vertically align a div. However, when the orientation changes, it causes the once vertically centered div to misposition, hence I tried writing some jquery to reload the window that will cause it to be centered once again. But the java is not working. So will be great if someone could point out to me, why it's not. Thanks.
CSS:
.vertical-align {
height:auto;
min-height: 100vh;
/* Make it a flex container */
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
/* Align the bootstrap's container vertically */
-webkit-box-align : center;
-webkit-align-items : center;
-moz-box-align : center;
-ms-flex-align : center;
align-items : center;
-webkit-box-pack : center;
-moz-box-pack : center;
-ms-flex-pack : center;
-webkit-justify-content : center;
justify-content : center;
flex-direction: row;
width:100%;
text-align: center;
font-size: 0;
}
Javascript:
var wasPortrait = -1;
var checkOrientation = function() {
var isPortrait = (window.innerHeight > window.innerWidth);
if( isPortrait === wasPortrait ) { return; // Nothing to do here }
wasPortrait = isPortrait;
alert("change dected");
location.reload();
};
window.addEventListener( 'orientationchange', checkOrientation, false );