Remove white space after Scale [duplicate] - html

This question already has answers here:
White space around css3 scale
(12 answers)
Closed 7 years ago.
I have a little problem with scale transformation. I wish resize element, but when I do, my old size occupies the space, and the next element undergoes this old size. How to remove this constraints ?
HTML
<!-- White space with Scale -->
<div class="scale"></div>
<div class="scale"></div>
<!-- Whitout Scale -->
<div></div>
<div></div>
CSS
div:nth-of-type(even) { background: blue; }
div:nth-of-type(odd) { background: red; }
div {
width: 100px;
height: 100px;
}
.scale {
transform: scale(0.5);
transform-origin: top left;
}
JSFiddle: https://jsfiddle.net/c7d2s21y/
Thank you for your response.

var scaleTo = 0.5,
itemWidth = $('.scaleB').width(),
itemHeight = $('.scaleB').height()
;
function scaleThis(meausure) {
var output = meausure * scaleTo;
return output;
}
$('.scaleB').on({
'mouseover': function(event) {
$(this).css({
'width' : scaleThis(itemWidth) + 'px',
'height' : scaleThis(itemHeight) + 'px'
});
},
'mouseout': function(event) {
$(this).css({
'width' : itemWidth + 'px',
'height' : itemHeight + 'px'
});
}
});
.wrapper {
background-color: #cccccc;
}
.wrapper:after {
content: "normal";
}
.wrapperScale {
background-color: #dddddd;
}
.wrapperScale:after {
content: "wrapped";
}
.wrapper_jQuery:after {
content: "jQuery";
}
.wrapper div:nth-of-type(even),
.wrapperScale div:nth-of-type(even) {
background: blue;
}
.wrapper div:nth-of-type(odd),
.wrapperScale div:nth-of-type(odd) {
background: red;
}
.scale, .wrapperScale div, .scaleB {
width: 50px;
height: 50px;
}
.scale:hover, .wrapperScale:hover {
transform: scale(0.5);
transform-origin: top left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="wrapper">
<!-- White space with Scale -->
<div class="scale"></div>
<div class="scale"></div>
</div>
<!-- Whitout Scale -->
<div class="wrapper wrapperScale">
<div></div>
<div></div>
</div>
<!-- jQuery -->
<div class="wrapper wrapper_jQuery">
<div class="scaleB"></div>
<div class="scaleB"></div>
</div>
That's that CSS transformations actually do, it doesn't affect the surrounding elements, you can try to wrap the DIVs inside another element and apply the scaling to that element, but it will not affect other elements outside, just the contents, other than that, you will have to manipulate the actual sizes from your DIVs via java Script or a js library such as jQuery.

You try this code i hope work for you :
<style>
div:nth-of-type(even) { background: blue; }
div:nth-of-type(odd) { background: red; }
div {
width: 100px;
height: 100px;
}
.scale {
transform: scale(1);
transform-origin: top left;
}
</style>

Related

How to create a splitted page with transitions

I`m trying to create a page, splitted horizontally or vertically. I want a nice transition between pages, splitted differently.
My solution is a background element with transform:rotateZ(0 or 90deg) and flex container with two elements:
<template>
<div id="app">
<div id="split-page-bg" :class="['split-' + splitType]"></div>
<div id="split-page" :style="{ 'flex-direction': flexDirection }">
<div id="split-page-part-first">
<p>Content #1</p>
<button #click="switchSplitType">{{ buttonText }}</button>
</div>
<div id="split-page-part-second">
<p>Content #2</p>
</div>
</div>
</div>
</template>
<script>
export default {
computed: {
buttonText() {
return (
"Switch to " +
(this.splitType === "horizontal" ? "vertical" : "horizontal")
);
},
flexDirection() {
return this.splitType === "horizontal" ? "column" : "row";
}
},
data() {
return {
splitType: "horizontal"
};
},
methods: {
switchSplitType() {
this.splitType =
this.splitType === "horizontal" ? "vertical" : "horizontal";
}
}
};
</script>
<style>
#app {
font-family: sans-serif;
font-size: 3rem;
height: 100vh;
width: 100vw;
padding: 0;
margin: 0;
}
#split-page-bg {
--w: max(200vw, 200vh);
--offset-percentage-vertical: 50vh;
--offset-percentage-horizontal: 50vw;
top: calc(-0.5 * var(--w) + 100vh - var(--offset-percentage-vertical));
left: calc(-0.5 * var(--w) + 100vw - var(--offset-percentage-horizontal));
width: var(--w);
height: var(--w);
position: fixed;
z-index: -10;
transition: transform 0.3s ease;
background: linear-gradient(0deg, #ff7d00 50%, #15616d 0%);
}
.split-horizontal {
--offset-percentage-vertical: 50vh;
}
.split-vertical {
transform: rotateZ(90deg);
}
#split-page {
width: 100vw;
height: 100vh;
display: flex;
}
#split-page-part-first {
flex: 0 1 50%;
}
#split-page-part-second {
flex: 0 1 50%;
}
button {
font: inherit;
}
</style>
Codepen
But it`s hard to work with separate background element. Sometimes background does not match with containers, there is a 1-2 px difference in width/height.
Question is, is there a better way for implementing this? Can I somehow animate containers like this and work with them in developer-friendly way?

Display a Search bar on header on scroll HTML/CSS

I have a search bar which would like to display onto the header on scroll, a great example is like the one on this site: https://www.indiamart.com/
Approach 1 - A simple way to do this would be to detect a scroll & add and remove a class that contains display: none;
You can have an event listener -
window.addEventListener('scroll', function() {
if( window.scrollY !== 0) {
document.getElementById('searchBar').classList.add('scrolled');
} else {
document.getElementById('searchBar').classList.remove('scrolled');
}
});
With the CSS -
.noScroll
{
background: yellow;
position:fixed;
height: 50px; /*Whatever you want*/
width: 100%; /*Whatever you want*/
top:0;
left:0;
display:none;
}
/*Use this class when you want your content to be shown after some scroll*/
.scrolled
{
display: block !important;
}
.parent {
/* something to ensure that the parent container is scrollable */
height: 200vh;
}
And the html would be -
<div class="parent">
<div class ='noScroll' id='searchBar'>Content you want to show on scroll</div>
</div>
Here's a JSFiddle of the same - https://jsfiddle.net/kecnrh3g/
Approach 2 -
Another simple approach would be
<script>
let prevScrollpos = window.pageYOffset;
window.onscroll = function() {
let currentScrollPos = window.pageYOffset;
if (prevScrollpos > currentScrollPos) {
document.getElementById('searchBar').style.top = '-50px';
} else {
document.getElementById('searchBar').style.top = '0';
}
prevScrollpos = currentScrollPos;
}
</script>
with the html -
<div class="parent">
<div id ='searchBar'>Content you want to show on scroll</div>
</div>
and css
#searchBar {
background: yellow;
position: fixed;
top: 0;
left: 0;
height: 50px;
width: 100%;
display: block;
transition: top 0.3s;
}
.parent {
height: 200vh;
}
Here's a JSFiddle of the same - https://jsfiddle.net/0tkedcns/1/
From the same example, the idea is only to show/hide once user scroll the page using inline css display property, you can do the same or at least provide a code sample so we can help you!
HTML
<div class="search-bar">
<div class="sticky-search">
Sticky Search: <input type="text" value="search" />
</div>
</div>
CSS
.sticky-search {
display:none;
position:fixed;
top:0px;
left:0px;
right:0px;
background:blue;
padding:10px;
}
JS
var searchHeight = $(".search-bar").outerHeight();
var offset = $(".search-bar").offset().top;
var totalHeight = searchHeight + offset;
console.log(totalHeight);
$(window).scroll(function(){
if($(document).scrollTop() >= totalHeight) {
$('.sticky-search').show();
} else {
$('.sticky-search').hide();
}
});

Having issues with vertical alignment (Flexbox) and center alignment

I'm using javascript to display dynamic text and image, but having trouble with formatting.
I'm using display: flex to put text and image next to each other, but am having trouble horizontally aligning them. Right now, it looks like:
But I'd like to horizontally align them so that it becomes:
I've tried the following, but this didn't work
#conA #container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
Update:
Implementing the following code but NOT setting the height of #heroText and #images the same
#conA #container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
does center text and images horizontally when both are present. However, once the images disappear, the text jumps. Here's how it's behaving https://imgur.com/a/7yYl8zO I'd like the text to not move when images disappear
Once I set the heights of #heroText and #images the same, it then turns to this:
I'm also looking to center the whole text+image in the parent div (#conA, which takes up full screen 100vh). I tried the following:
#conA {
position: relative;
}
#conA #container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
But it looks odd b/c text keeps moving/jumping depending on whether there's an image displayed.
So when there's no image, it looks like:
When when images appear, text moves to left so that the whole thing becomes centered:
How can I fix the position of text here? I'd like the whole thing is centered when there's an image. So when there's no image:
When there's an image:
html
<section id="conA">
<div id="container">
<div id="heroText">
<div id="text-fixed">I'm a fixed text</div>
<div id="text"></div>
</div>
<div id="images"></div>
</div>
</section>
css
#conA {
height: 100vh;
position: relative;
}
#conA #container {
margin: 0;
}
#conA #text {
display: initial;
border-right: 3px solid #56525E;
}
#heroText {
line-height: 1.7;
font-size: 30px;
width: 800px;
}
#conA #container {
margin: 0;
display: flex;
}
#heroText {
height: 400px;
}
#conA #images {
height: 400px;
}
#conA img
{
display:none;
height: 400px;
}
#conA img.invisible
{
visibility: hidden;
}
#conA img.show
{
display:inline;
}
#conA img.anim1
{
animation-duration: 2000ms;
}
#conA img.anim2
{
animation-duration: 2000ms;
}
#conA img.anim3
{
animation-duration: 2000ms;
}
.fadeIn
{
animation-name: fadeIn;
}
#keyframes fadeIn
{
0% {opacity: 0;}
100% {opacity: 1;}
}
.fadeOut
{
animation-name: fadeOut;
}
javascript code for dynamic display of text and image
// List of sentences
var _CONTENT = [ "I'm the first sentence.", "I'm the second sentence."
, "I'm the third sentence.", "I'm the fourth sentence." ];
var IMAGE_URLS = ['img/image1.png', 'img/image2.jpg', 'img/image3.png', 'img/image1.png','img/image2.png','img/image3.png', 'img/image4.png','img/image5.png'];
var IMAGES = jQuery.map(IMAGE_URLS, function (url, index){
var img = document.createElement('img');
img.setAttribute('src', url);
img.classList.add('anim'+((index%2)+1));
img.classList.add('fadeOut');
document.getElementById('images').appendChild(img);
return img;
});
// Current sentence being processed
var _PART = 0;
// Character number of the current sentence being processed
var _PART_INDEX = 0;
// Holds the handle returned from setInterval
var _INTERVAL_VAL;
// Element that holds the text
var _ELEMENT = document.querySelector("#text");
// Implements typing effect
function Type() {
var text = _CONTENT[_PART].substring(0, _PART_INDEX + 1);
_ELEMENT.innerHTML = text;
_PART_INDEX++;
// If full sentence has been displayed then start to delete the sentence after some time
if(text === _CONTENT[_PART]) {
var imgIndexBase = _PART*2;
IMAGES[imgIndexBase].classList.remove('fadeOut');
IMAGES[imgIndexBase+1].classList.remove('fadeOut');
setTimeout(function () { IMAGES[imgIndexBase].classList.add('fadeIn'); }, 0);
setTimeout(function () { IMAGES[imgIndexBase].classList.add('show'); }, 0);
setTimeout(function () { IMAGES[imgIndexBase].classList.add('fadeOut'); }, 2000);
setTimeout(function () { IMAGES[imgIndexBase].classList.remove('fadeOut'); }, 3000);
setTimeout(function () { IMAGES[imgIndexBase].classList.remove('show'); }, 3000);
setTimeout(function () { IMAGES[imgIndexBase + 1].classList.add('fadeIn'); }, 0);
setTimeout(function () { IMAGES[imgIndexBase + 1].classList.add('show'); }, 0);
setTimeout(function () { IMAGES[imgIndexBase + 1].classList.add('fadeOut'); }, 2000);
setTimeout(function () { IMAGES[imgIndexBase + 1].classList.remove('fadeOut'); }, 3000);
setTimeout(function () { IMAGES[imgIndexBase + 1].classList.remove('show'); }, 3000);
clearInterval(_INTERVAL_VAL);
setTimeout(function() {
_INTERVAL_VAL = setInterval(Delete, 50);
}, 4000);
}
}
// Implements deleting effect
function Delete() {
var text = _CONTENT[_PART].substring(0, _PART_INDEX - 1);
_ELEMENT.innerHTML = text;
_PART_INDEX--;
// If sentence has been deleted then start to display the next sentence
if(text === '') {
clearInterval(_INTERVAL_VAL);
// If last sentence then display the first one, else move to the next
if(_PART == (_CONTENT.length - 1))
_PART = 0;
else
_PART++;
_PART_INDEX = 0;
// Start to display the next sentence after some time
setTimeout(function() {
_INTERVAL_VAL = setInterval(Type, 100);
}, 500);
}
}
// Start the typing effect on load
_INTERVAL_VAL = setInterval(Type, 100);
See example below using flex CSS. First section with image, second section with no images in .images div.
There is a lot to explain with flex, but it is super powerful when it comes to dynamic layout. Hope this gets you on the right track.
Also you need to relax on your id attribute usage, valid html only allow single usage of an id attribute value. Use class attribute for multiple instances, and id for single usage instances.
id attribute value should only ever be used once, never multiple times.
BODY {
padding: 1rem;
margin: 0;
}
SECTION .container {
border: 1px black solid;
padding: 2rem;
display: flex;
align-items: center;
flex-wrap: wrap;
flex-direction: initial;
min-height: 100px;
justify-content: center;
margin-bottom: 1rem;
}
SECTION .container .hero-text {
width: 50%;
background: cyan;
}
SECTION .container .images {
width: 50%;
background: red;
}
SECTION .container .images IMG {
display: block;
width: 100%;
}
<section>
<div class="container">
<div class="hero-text">
<div class="text-fixed">I'm a fixed text</div>
<div class="text">And I am loving life :)</div>
</div>
<div class="images">
<img src="https://i.imgur.com/q5Y5RCH.png" alt="" />
</div>
</div>
</section>
<section>
<div class="container">
<div class="hero-text">
<div class="text-fixed">I'm a fixed text</div>
<div class="text">And I am loving life :)</div>
</div>
<div class="images">
<!-- no images -->
</div>
</div>
</section>

Containers are not inline in my Vue Swiper

I have written simple swiper on in my vue app but I have a problem with containers which are not inline. The second is under the first one.
The second problem is that slider element should be visible only in viewport of swiper but it is not (viewport is border is blue).
I want to achieve a pretty effect of fluent slide show.
You can see it in my example:
https://jsfiddle.net/eywraw8t/547878/
How can I fix it?
<template>
<div class="swiper">
<transition-group
tag="div"
class="slides-group"
:name="transitionName"
>
<div :key="currentIndex" class="slide">
<slot v-bind:element="current" />
</div>
</transition-group>
<div class="pagination">
<button #click="next">next</button>
</div>
</div>
</template>
<script>
export default {
props: {
data: {
type: Array,
default: []
}
},
data() {
return {
currentIndex: 0,
transitionName: 'slide-next'
}
},
computed: {
current() {
return this.data[this.currentIndex];
}
},
methods: {
next() {
this.currentIndex++;
}
}
}
</script>
<style lang="scss" scoped>
.swiper {
width: 100%;
position: relative;
}
.slide-next-enter-active,
.slide-next-leave-active {
transition: transform 0.5s ease-in-out;
}
.slide-next-enter {
transform: translate(100%);
}
.slide-next-leave-to {
transform: translate(-100%);
}
.slide-prev-enter-active,
.slide-prev-leave-active {
transition: transform 0.5s ease-in-out;
}
.slide-prev-enter {
transform: translate(-100%);
}
.slide-prev-leave-to {
transform: translate(100%);
}
</style>
Try the following CSS changes
1)
to .swiper, add:
overflow:hidden;
2)
to .slide, add:
display: inline-block;
Then, change your transition settings for aesthetics.
.swiper {
margin-left: 100px;
position: relative;
border: 1px solid blue;
overflow:hidden;
}
.slide {
border: 1px solid red;
width: 200px;
height: 200px;
display:inline-block;
}
Please note, using an inline display will cause it to break into multi-lines if the line width exceeds the containers width.
You may want to set absolute displays on them with fixed positions, and manipulate those positions to achieve the desired affect.

Transform scale keeps the original space around the scaled element

I have two nested divs. The inner one is transform: scale(0.5).
Both are display: inline-block;.
What I need to happen is the outer div fits it's width to the width of the inner one. That's what I supposed to happen but not. What occur is that the outer div «thinks» the inner div has it's original size.
The outer div fits it's width to the inner's width only if the inner div is transform: scale(1) but not using an scale factor less than 1, for example: 0.5 (see example).
I need some way to achieve this by CSS in an elegant way.
.red {
background-color: #f00;
}
.green {
background-color: #0f0;
}
.box_1,
.box_2 {
display: inline-block;
}
.box_1 {
width: 300px;
height: 300px;
transform: scale(0.5);
transform-origin: left top;
}
<div class="box_2 green">
<div class="box_1 red">Hello World</div>
</div>
Any idea on how to solve this?
A brutal way would be to virtually reduce space needed by element.
Your example shows a known width & height, so it makes it easy. else you would need a javascript method.
.box_1 {
width: 300px;
height: 300px;
transform: scale(0.5);
transform-origin: left top;
margin-bottom:-150px;
margin-right:-150px;
}
https://jsfiddle.net/0bc4sxk3/1/
Scaling up would mean positive margins.
Transform only happens at screen, elements still use initial room and place needed in the flow of the document.
I think that one solution is to wrap the scaled-down element into an element with overflow: hidden.
The wrapper should have the exact dimensions of the scaled-down content.
This solution was best for me.
.wrapper {
width: 150px;
height: 150px;
overflow: hidden;
}
.content {
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 300px;
transform: scale(0.5);
transform-origin: left top;
}
.box_1,
.box_2 {
display: inline-block;
}
.red {
background-color: #f00;
}
.green {
background-color: #0f0;
}
<div class="box_2 green">
<div class="box_1 red">Hello World</div>
</div>
Coming late to the party, but another way is to use a sizing element that is empty, not scaled, has the same external size as the scaled down element and sits underneath the scaled element. This drives the sizing of the parent, and the scaled element is then positioned absolutely on top of the sizing element.
.red { background-color: #f00; }
.green { background-color: #0f0; }
.blue { background-color: #00f; }
.container {
position: relative;
display: inline-block;
}
.sizingBox {
width: 150px;
height: 150px;
}
.content {
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 300px;
transform: scale(0.5);
transform-origin: left top;
}
<div class="container green">
<div class="sizingBox blue"></div>
<div class="content red">Hello World</div>
</div>
If someone is looking for a copy-pasta React Componet, this seems to work based on Guy's code:
import * as React from "react";
interface Props
extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
scale?: number;
style?: React.CSSProperties;
fullHeight: number;
fullWidth: number;
}
export const ScaleBox: React.FC<Props> = ({
scale = 1,
style,
fullWidth,
fullHeight,
children,
...rest
}) => {
return (
<div
data-comment={"ScaleBox Container"}
style={{ position: "relative", display: "inline-block", ...style }}
{...rest}
>
<div
data-comment={"ScaleBox Sizing Box"}
style={{ width: fullWidth * scale, height: fullHeight * scale }}
></div>
<div
data-comment={"ScaleBox Content"}
style={{
transform: `scale(${scale})`,
transformOrigin: "top left",
position: "absolute",
top: 0,
left: 0,
}}
>
{children}
</div>
</div>
);
};
Even later, I've built on mikeysee's React component and written one that works with content that sizes dynamically (it uses negative margins to avoid resizing the children's content):
import * as React from 'react';
import useResizeObserver from '#react-hook/resize-observer';
interface Props
extends React.DetailedHTMLProps<
React.HTMLAttributes<HTMLDivElement>,
HTMLDivElement
> {
scale?: number;
style?: React.CSSProperties;
}
/**
* The ScaleBox is an element that scales its content using CSS transform scale
* and makes sure the flow around the box is as if the box had the size
* according to the applied scale.
*
* The parent element of a ScaleBox must have the overflow: 'hidden' style.
*/
export const ScaleBox: React.FC<Props> = ({ scale = 1, style, children }) => {
const [marginX, setMarginX] = React.useState('0px');
const [marginY, setMarginY] = React.useState('0px');
const divRef = React.useRef<HTMLDivElement>(null);
useResizeObserver(divRef, (target) => {
setMarginX(`${(scale - 1) * target.contentRect.width}px`);
setMarginY(`${(scale - 1) * target.contentRect.height}px`);
});
React.useEffect(() => {
if (divRef.current) {
setMarginX(`${(scale - 1) * divRef.current.offsetWidth}px`);
setMarginY(`${(scale - 1) * divRef.current.offsetHeight}px`);
}
}, [scale]);
return (
<div
ref={divRef}
style={{
...style,
transform: `scale(${scale})`,
transformOrigin: 'top left',
marginRight: marginX,
marginBottom: marginY
}}
>
{children}
</div>
);
};