How to center object with CSS transform scale - css

I'm trying to implement a zoom in/out functionality, just like you would have on a document editor like google docs or any word processor application. The problem I'm having is that I cannot keep the "document" centered and also be able to scroll all of its parts into view. Here is a small demonstration of the problem: https://codepen.io/liviu_vasut/pen/dyGbwwO
document.getElementById('objectToScale').style.transform = "scale(3)";
.container {
display: flex;
align-items: center;
justify-content: center;
padding: 5px;
width: 300px;
height: 200px;
border: 1px solid #000000;
left: 0px;
top: 0px;
margin: 10px;
overflow: auto;
}
.object {
position: relative;
width: 120px;
height: 120px;
display: inline-block;
background-color: grey;
border-radius: 25px;
padding: 5px;
transform-origin: center;
transform: scale(1);
}
<div class="container">
<div id="objectToScale" class="object">x</div>
</div>
Thanks for your time.

You scale only some inner element inside the whole box, but expect see the whole box scaled. if you want to scale the white padding and all the inner content to stay visible (and be able to scroll to) you should add some wrapper inside with width: 100% and height: 100%, and scale it, so the whole content become scaled.
Also, as #HaoWu mentioned, you should set the transform-origin to 0 0.
The final product should look somewhat like this:
var scaled = false;
function toggleScale() {
var objects = document.getElementsByClassName('wrapper');
for (var i = 0; i < objects.length; i++) {
objects[i].style.transform = scaled ? 'scale(1)' : 'scale(3)';
}
scaled = !scaled;
}
.container {
width: 300px;
height: 200px;
border: 1px solid #000000;
left: 0px;
top: 0px;
margin: 10px;
overflow: auto;
}
.wrapper {
width: 100%;
height: 100%;
display: flex;
box-sizing: border-box;
align-items: center;
justify-content: center;
padding: 5px;
transform-origin: 0 0;
}
.object {
position: relative;
width: 120px;
height: 120px;
display: inline-block;
background-color: grey;
border-radius: 25px;
padding: 5px;
transform-origin: center;
transform: scale(1);
}
<input type="button" onclick="toggleScale()" value="Toggle Scale" />
<div class="container">
<div class="wrapper">
<div id="objectToScale" class="object">x</div>
</div>
</div>

Actually, use the transform-origin: 0 0; and manually set the scrollbar to the center:
var scaled = false;
function toggleScale() {
[...document.getElementsByClassName('object')].forEach(e => {
e.classList.toggle('scaled');
e.parentElement.scrollTop = (e.parentElement.scrollHeight - e.parentElement.clientHeight) / 2;
e.parentElement.scrollLeft = (e.parentElement.scrollWidth - e.parentElement.clientWidth) / 2;
});
}
* {
box-sizing: border-box;
}
.container {
display: flex;
align-items: center;
justify-content: center;
padding: 5px;
width: 300px;
height: 200px;
border: 1px solid #000000;
left: 0px;
top: 0px;
margin: 10px;
overflow: auto;
}
.object {
position: relative;
width: 120px;
height: 120px;
display: inline-block;
background-color: grey;
border-radius: 25px;
padding: 5px;
transform-origin: 0 0;
}
.scaled {
transform: scale(3);
}
<input type="button" onClick="toggleScale()" value="Toggle Scale" />
<div class="container">
<div class="object">cannot see the entire object when scaled</div>
</div>

Related

How to use CSS to modify the style like a design draft

I encountered a problem. I made a progress bar that will run to the corresponding position according to the value of progress. But I don't quite know how to modify the dot into a pattern like the design draft of the attached drawing, so that it can be wrapped in the progress-bar.
// 假設後端傳來的值是30
var progress = 10;
// 計算小圓點的位置
var dot = document.getElementById("dot");
var dotPosition = (progress / 30) * 100;
dot.style.left = dotPosition + "%";
body {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
#progress-bar-container {
width: 600px;
height: 5px;
background-color: #fff;
position: relative;
display: flex;
flex-wrap: nowrap;
}
.progress-bar {
width: 33.33%;
height: 5px;
background-color: #fff;
margin-right: 8px;
border-radius: 20px;
}
#progress-bar-1 {
background-color: #ddd;
}
#progress-bar-2 {
background-color: #ddd;
}
#progress-bar-3 {
background-color: #ddd;
margin-right: 0;
}
#dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: orange;
position: absolute;
top: -3px;
left: 0;
transition: left 0.2s ease-out;
}
<div id="progress-bar-container">
<div class="progress-bar" id="progress-bar-1"></div>
<div class="progress-bar" id="progress-bar-2"></div>
<div class="progress-bar" id="progress-bar-3"></div>
<div id="dot"></div>
</div>

Using multiple mix blend modes under a single parent

Just for fun I decided to make a progress bar element.. I also wanted to add a circular blob in the progress bar.
var modelList = [
'normal',
'multiply',
'screen',
'overlay',
'darken',
'lighten',
'color-dodge',
'color-burn',
'hard-light',
'soft-light',
'difference',
'exclusion',
'hue',
'saturation',
'color',
'luminosity'
]
let elem =
document.querySelector('.box');
let modelElem =
document.querySelector('.circle');
let progressBar =
document.querySelector('.progress');
let i = 0;
modelElem.innerHTML = modelList[i];
elem.onclick = function(){
if(i+1 < modelList.length) i++;
else i = 0;
progressBar.style.mixBlendMode= modelList[i];
modelElem.innerHTML = modelList[i];
}
* {
box-sizing: border-box;
}
.box {
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
cursor: pointer;
1
}
.aaline {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
height: 40px;
width: 80%;
border: 8px solid black;
background: white;
z-index: 2;
}
.circle {
position: absolute;
height: 250px;
width: 250px;
border: 8px solid black;
border-radius: 50%;
background: white;
text-align: center;
font-size: 3rem;
z-index: 1;
}
.circle:first-of-type {
mix-blend-mode: lighten;
}
.progress {
position: absolute;
width: 20%;
height: 250px;
background: brown;
left: 0;
}
<div class="box">
<div class="aaline">
<div class="circle">
There.. There..
</div>
<div class="progress"></div>
</div>
<div class="circle"></div>
</div>
Adding mix blend mode to progress bar so that it blends in nicely with the aaline is the problem. I don't know why, but it is not blending.
Edit: toggling blends js

For a picture preview I need to put 2 div elements vertically in front of a picture

For a picture preview I want to put 2 invisble divs (red/blue in the picture) in front of a picture for next/previous image functionality.
I would like to have the div ("pictureContainer"/ green bordered zone) to automatically take over the dimension of the containing picture but I can't find a PURE CSS solution without setting the width and the height manually.
.container {
position: fixed;
width: 100%;
height: 100%;
border: 3px solid black;
}
.pictureContainer {
/* I don't want to set width and hight manuyally.
The container should have the size if the contained image. */
height: 50%;
width:300px;
position: relative;
margin: auto;
border: 3px solid green;
}
.leftSide {
background-color: blue;
float: left;
height: 100%;
width: 50%;
opacity: 80%;
}
.rightSide {
background-color: red;
float: right;
height: 100%;
width: 50%;
opacity: 80%;
}
.picture {
position: absolute;
top: 0;
left: 0;
margin: auto;
z-index: -1;
}
<div class="container">
<div class="pictureContainer">
<div class="leftSide"></div>
<img class="picture" src="https://www.9skips.com/wp-content/uploads/2018/01/anger-300x300.jpg">
<div class="rightSide"></div>
</div>
</div>
Also the container should be horizontally aligned.
Note: The full screen white div with the black border is used to close the picture preview.
You should change so the divs have absolut: position, let the image have it's natural size, container should be display: inline-block;
.container {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
width: 100%;
height: 100%;
border: 3px solid black;
}
.pictureContainer {
position: relative;
display: inline-block;
margin: 0 auto;
border: 3px solid green;
}
.picture {
display: block;
}
.leftSide {
position: absolute;
top: 0;
bottom: 0;
left: 0;
background-color: blue;
width: 50%;
opacity: 80%;
z-index: 1;
}
.rightSide {
position: absolute;
top: 0;
bottom: 0;
right: 0;
background-color: red;
height: 100%;
width: 50%;
opacity: 80%;
z-index: 1;
}
<div class="container">
<div class="pictureContainer">
<div class="leftSide"></div>
<img class="picture" src="https://www.9skips.com/wp-content/uploads/2018/01/anger-300x300.jpg">
<div class="rightSide"></div>
</div>
</div>

css overlapping circle and text box

I am trying to produce this effect with CSS. I have tried creating a box with a triangle and then using negative margin to overlap it onto the circle, but cannot get it right.
Many thanks for any help.
fiddle
https://jsfiddle.net/Hastig/n3w0tztv/
Getting the circle to stay vertically centered and have the text container min-height the height of circle is tricky and is not worked out in this example. A cheap fix is adding align-items: center to .container at a breakpoint with #media.
body {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
background-color: white;
height: 100vh;
}
.container {
display: flex;
width: 100%;
padding: 10px;
overflow: hidden;
}
.left {
position: relative;
display: flex;
width: 150px;
height: 150px;
margin-top: -4px;
margin-bottom: -4px;
margin-right: -17px;
background-color: #ec847c;;
border-style: solid;
border-color: white;
border-width: 4px;
border-radius: 100%;
z-index: 10;
}
.right {
position: relative;
display: flex;
flex: 2;
font-size: 20px;
color: white;
background-color: #4ca132;
}
.square {
position: absolute;
left: 0;
width: 50px;
height: 50px;
background-color: white;
overflow: hidden;
}
.square-top { top: 0; }
.square-btm { bottom: 0; }
.square::before {
content: "";
position: absolute;
display: flex;
width: 100%;
height: 100%;
transform: rotate(45deg) scale(2);
background-color: #4ca132;
z-index: 1;
}
.square-top::before { top: 50%; left: 50%; }
.square-btm::before { bottom: 50%; left: 50%; }
.text {
position: relative;
z-index: 2;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
padding: 20px 20px 20px 40px;
}
<div class="container">
<div class="left">
</div>
<div class="right">
<div class="square square-top"></div>
<div class="square square-btm"></div>
<div class="text">
Roles play an extremely important part in family funtion.
</div>
</div>
</div>

Fixed position inside relative container (modal with fixed header)

I am trying to create a modal with a fixed header. This was all working fine but we have since added a custom scroll bar in webkit browsers using ::-webkit-scrollbar. When we did this it causes the fixed header to be wider then the modal by the width of the custom scroll.
** edit: this is only an issue when resizing the window/when min-width kicks in **
My understanding is the fixed header is calculating its max width of 90% based on the whole window and the modal is calculating 90% based on the available space not including the scrollbar.
There are two css ways of fixing this that I can think of.
1) figure out if I am just being silly and there is a way of making a fixed element depend on the size of the relative parent.
2) if the body or the parent div of the modal has the pseudo selector add styles.
Sadly the following does not work:
div::-webkit-scrollbar ._common-modal.is-open, body::-webkit-scrollbar ._common-modal.is-open{
width:calc(100% - $scrollbarwidth );
}
Any thoughts?
css :
.modal-overlay {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.2);
z-index: 100;
}
div::-webkit-scrollbar ._common-modal.is-open, body::-webkit-scrollbar ._common-modal.is-open {
display: none;
}
._common-modal.is-open {
bottom: 0;
left: 0;
outline: 0;
overflow-x: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
position: absolute;
right: 0;
top: 0;
padding: 20px 0;
text-align: center;
z-index: 101;
}
._common-modal.is-open.header-detached .modal-header {
position: fixed;
top: -1px;
width: inherit;
max-width: 90%;
}
._common-modal.is-open.header-detached .modal-header:after {
content: '';
position: absolute;
bottom: -4px;
left: 0;
right: 0;
height: 3px;
background: rgba(85, 85, 85, 0.05);
}
._common-modal.is-open.header-detached .modal-content {
margin-top: 50px;
}
._common-modal.is-open:before {
content: " ";
display: inline-block;
height: 100%;
vertical-align: middle;
}
._common-modal.is-open .wkModal {
text-align: left;
position: relative;
max-width: 90%;
width: 500px;
z-index: 2;
background: #ffffff;
border: 1px solid grey;
display: inline-block;
vertical-align: middle;
}
._common-modal.is-open .modal-header {
border-bottom: 1px solid grey;
padding: 0 15px;
line-height: 51px;
background-color: #fff;
z-index: 2;
}
._common-modal.is-open .modal-footer {
padding: 0 15px;
line-height: 50px;
}
._common-modal.is-open .modal-title {
font-size: 20px;
text-align: center;
font-weight: 300;
width: 80%;
margin: 0 auto;
}
._common-modal.is-open .modal-close {
position: absolute;
top: 0;
right: 0;
width: 50px;
height: 50px;
display: block;
background: url(../img/blue_small-x.svg) no-repeat center center;
}
._common-modal.is-open .modal-content {
padding: 10px 15px;
}
._common-modal.is-open .modal-content p {
text-align: center;
}
html:
<div class="_common-modal is-open">
<div class="wkModal">
<div class="modal-header" >
<div class="modal-title">
<span >Large Modal Custom</span>
</div><a class="modal-close"
></a>
</div>
<div class="modal-content" >
<h1 Test Modal Content</h1>
<div>
**content**
</div>
</div>
<div class="modal-footer"></div>
</div>
</div>

Resources