Using jquery to scale some text with mousemove but can't figure out how to make the word on the right (h2) scale out to the left from the right side of the word from the fixed right position. Instead it always scales from the left edge of the word.
I want the 2 words combined to fill the width of the window at all times and as the cursor moves left, the left word (h1) shrinks and the right word (h2) grows and vice versa.
There is also a problem that I am using some script to scale each word to 50% of the window width on document.ready, but again the right word (h2) scales from its original position based on the css font size and so scales off the page.
Using text-align: right has no effect. How can I keep the right word contained in the window and scale out to the left? jsFiddle
var originwidth = $('h1').width()
var originheight = $('h1').height()
var origh1scalex = $(window).width()/2 / $('h1').width()
var origh2scalex = $(window).width()/2 / $('h2').width()
$(function() {
$('h1').css('transform', 'scaleX(' + origh1scalex + ')');
$('h2').css('transform', 'scaleX(' + origh1scalex + ')');
});
$(document).on('mousemove', function(event) {
var scaleX = event.pageX / originwidth
var scaleY = event.pageY / originheight
$('h1').css('transform', 'scale(' + scaleX + ',' + scaleY + ')')
})
var originwidth = $('h2').width()
var originheight = $('h2').height()
$(document).on('mousemove', function(event) {
var scaleX = ($(window).width() - event.pageX) / originwidth
var scaleY = event.pageY / originheight
$('h2').css('transform', 'scale(' + scaleX + ',' + scaleY + ')')
})
h1,
h2 {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
hgroup {
display: block;
}
body {
line-height: 1;
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
body {
font-family: Arial;
font-size: 32px;
line-height: 1.5;
background-color: #ffdc00;
color: #333333;
}
h1 {
font-size: 5vw;
font-weight: 700;
position: fixed;
top: 0;
left: 0;
transform-origin: 0 0;
}
h2 {
font-size: 5vw;
font-weight: 700;
position: fixed;
top: 0;
right: 0;
transform-origin: 0 0;
text-align: right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>LSNR.B</h1>
<h2>DESIGN</h2>
I've made several improvements and here is the result: https://codepen.io/adelriosantiago/pen/RwryoLj?editors=1010
The issue was a missing transform-origin: top right; on the CSS of H2. This sets the origin point where all translations, scale and rotations will be made.
Also originwidth was needed to be calculated inside the mousemove event because it changes every time the transform is calculated.
A few other improvements made are:
Only one mousemove event is now used.
String template literals like scale(${ scaleX }, ${ scaleY }) are used so that it is easier to discern how the string is built.
This further version allows setting a size when the page is loaded first time and no mousemove event has happened yet: https://codepen.io/adelriosantiago/pen/vYLjybR?editors=0111
Related
I'm trying to shift an element to the left by using transform. However, there is already an existing property on the style transform which looks like this: transform: translate3d(tx, ty, tz)
What I want to do is in addition of the translate3d(tx, ty, tz), I want to add another property called translateX(tx). So the whole style will look like this:
transform: translate3d(tx, ty, tz) translateX(tx)
Is there a way to do this in CSS? I don't want to overwrite the existing style property but add onto it.. My project is in Angular so would I have to do some code in the component end? Any help is greatly appreciated!
EDIT: I should also mention that the translate3d style is already defined for the element, not in my css file but by default (I'm using a library that sets the style for the element already). What I am trying to figure out is how to grab the current style, which is transform: translate3d AND add the translateX style to it as well so that it looks like:
transform: translate3d(tx, ty, tz) translateX(tx)
I will say it again, I do not set the translate3d in my own css file but it's a style that is automatically set for that specific element because of the library. If it helps, the library I am using is Leaflet for Angular
One quick and dirty way to achieve this effect would be to take advantage of relative positioning, using the following CSS properties:
position: relative
left: [tx]
Working Example:
.my-heading-a,
.my-heading-b {
position: relative;
transform: translate3d(40px, 20px, 10px);
}
.my-heading-a {
left: 0;
}
.my-heading-b {
left: 80px;
}
<h2 class="my-heading-a">My Heading A</h2>
<h2 class="my-heading-b">My Heading B</h2>
Update 2
No more custom variables. This example directly changes the translate3d's x value. Note: I mostly copied the getTransform function from another SO post.
const myEl = document.querySelector(".myElement");
const MOD = 10;
const getTransform = el => {
var transform = window.getComputedStyle(el, null).getPropertyValue('-webkit-transform');
var results = transform.match(/matrix(?:(3d)\(-{0,1}\d+(?:, -{0,1}\d+)*(?:, (-{0,1}\d+))(?:, (-{0,1}\d+))(?:, (-{0,1}\d+)), -{0,1}\d+\)|\(-{0,1}\d+(?:, -{0,1}\d+)*(?:, (-{0,1}\d+))(?:, (-{0,1}\d+))\))/);
if (!results) return [0, 0, 0];
if (results[1] == '3d') return results.slice(2, 5);
results.push(0);
return results.slice(5, 8);
}
document.querySelector(".button").addEventListener("click", () => {
const [x, y, z] = getTransform(myEl);
const newX = parseInt(x, 10) + MOD;
myEl.style.transform = `translate3d(${newX}px, ${y}, ${z})`;
});
.myElement {
transform: translate3d(100px, 0, 0);
display: inline-block;
padding: 1rem;
background-color: tomato;
color: white;
transition: 0.3s transform;
}
.button {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: gray;
padding: .5rem 0;
color: white;
font-size: 1.4rem;
}
<div class="myElement">Test</div>
<button class="button">Move it</button>
Update
This will work and add 10px onto the initial x translation in the translate3d:
/* 200px + 10px = 210px x translation */
transform: translate3d(200px, 0, 0) translateX(10px);
div {
background-color: red;
padding: 1rem 2rem;
display: inline-block;
transform: translate3d(200px, 0, 0) translateX(10px);
}
<div></div>
Original Answer
Instead of this pattern…
transform: translate3d(tx, ty, tz) translateX(tx);
…you could set up the translate3d properties so they consume custom properties up front, and update the individual values as necessary.
transform: translate3d(var(--tx), var(--ty), var(--tz));
In the following example, I'm updating individual custom properties to move the box down and to the right. Note that nothing is overwritten and we have total control over the changes we'd like to make.
document.querySelector(".button").addEventListener("click", () => {
const style = document.documentElement.style;
style.setProperty("--tx", "120%");
style.setProperty("--ty", "80px");
});
:root {
--tx: 100%;
--ty: 40px;
--tz: 0;
}
.myElement {
transform: translate3d(var(--tx), var(--ty), var(--tz));
display: inline-block;
padding: 1rem;
background-color: tomato;
color: white;
transition: 0.3s transform;
}
.button {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: gray;
padding: .5rem 0;
color: white;
font-size: 1.4rem;
}
<div class="myElement">Test</div>
<button class="button">Move it</button>
I am learning Vue and really enjoying it. I have a tab that I want fixed to the bottom of the browser window when the page loads. When a user clicks the tab, it will slide up to show some content.
Everything is working great. I am able to have the tab stick to the bottom of the page - and click events are working great as well.
The problem I am having is that I need to calculate the height of tab (and div) to set the CSS property correctly. When the page loads, you can see the tab slide down into place. I would like to hide the tab until everything has been calculated and it's in the correct place.
Here is what I'm using:
app.js
new Vue({
el: '#info',
delimiters: ['${', '}'],
data: {
active: false,
inactive: true,
styles: {
'bottom': 0
},
},
methods() {
toggle: function (event) {
event.preventDefault();
this.active = !this.active;
this.inactive = !this.inactive;
}
},
mounted() {
let tabHeight = this.$refs.infoTab.clientHeight;
let boxHeight = this.$refs.infoBox.clientHeight; // 473px
this.styles.bottom = -boxHeight + 'px';
}
});
HTML
<div class="info not-active" id="info" #click="toggle" ref="infoTab"
v-cloak
v-bind:class="{ active: active }"
v-bind:style="styles">
<!-- content -->
</div>
style.css
[v-cloak] {
display: none;
}
/* more classes */
.info {
width: 100%;
position: fixed;
&.inactive {
bottom: -100%;
}
&.active {
bottom: 0 !important;
}
}
I know I am close, I just don't want users to see the tab slide into place. It should just be there. I tried using the created hook, but clientHeight is not available.
Any suggestions are greatly appreciated!
I think you can solve this just using CSS, no need to use any of Vue's lifecycle hooks, I made a pen with a vanilla JS example:
let infoNode = document.getElementById('info');
infoNode.addEventListener('click', () => {
if (infoNode.style.top) {
// clear inline top style
infoNode.style.top = '';
} else {
// set top to client height + 2 * border thickness
infoNode.style.top = `calc(100% - ${infoNode.clientHeight}px - 4px)`;
}
});
#info {
font-size: 16px;
width: 200px;
border: 2px solid hsl(0, 0%, 80%);
padding: 8px;
border-radius: 4px;
cursor: pointer;
position: fixed;
/* 100% height of the viewport subtracting:
tab height: padding, margin, & font size */
top: calc(100% - (8px + 8px + 24px));
/* we center the tab horizontally here using
50% the width of the viewport - 50% the fixed
width of the tab */
left: calc(50% - 200px/2);
transition: top 0.5s;
}
.title {
font-size: 24px;
font-weight: 500;
margin-bottom: 8px;
display: block;
}
p {
margin: 0;
}
<div id="info">
<span class="title">Click on Me</span>
<p>
This is the content of the tab, isn't it great? I think so too, and it can be of any arbitrary length!
</p>
</div>
Basically the trick is to use calc with top instead of -100% with bottom for your positioning, then your tab is initially rendered in the correct position and you don't have to worry it being out of place when a visitor first loads your page.
I am by no means a CSS expert (as you can see from my code) but I almost got this working the way I want but I was having some slight formatting problems. Basically I am trying to make a page that will go through a ppt deck (exported as .jpgs). It is extremely straight forward with only 2 buttons that go to the next or previous slide and displays the image full screen.
The issue I am seeing is the image keeps getting cropped, specifically the top. It will often display fine but when I switch images the top 5ish% of the screen is getting clipped no matter how much I play with the padding. Hopefully this is an easy fix... any help would be greatly appreciated...
<html>
<head>
<style>
body, html {
height: 100%;
}
.bg {
/* The image used */
background-image: url("Slide1.JPG");
/* Full height */
height: 90%;
/* Center and scale the image nicely */
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.center {
position: relative;
vertical-align: middle;
top: 100%;
}
.button {
background-color: #0033ff; /* Blue */
border: solid;
border-width: medium;
border-color: black;
color: white;
padding: 2px 2px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
vertical-align: text-top;
height: 5%;
width: 40%;
font-size: 100%;
}
</style>
<script src="jquery-3.2.1.min.js"></script>
<script type="text/javascript">
var refreshIntervalId = setInterval(autoNextSlide, 8000);
var clicks = 1;
var isPaused = false;
var time = 0;
function pictureBack() {
clicks -= 1;
checkImage("Slide" + clicks + ".JPG", function () { }, function () { clicks = 1; });
// alert("slides/Slide" + clicks + ".JPG");
var str_image = 'background-image: url("Slide' + clicks + '.JPG");';
document.getElementById('bkground').style.cssText = str_image
isPaused = true;
time = 0;
}
function pictureNext() {
clicks += 1;
checkImage("Slide" + clicks + ".JPG", function () { }, function () { clicks = 1; });
//alert("slides/Slide" + clicks + ".JPG");
var str_image = 'background-image: url("Slide' + clicks + '.JPG");';
document.getElementById('bkground').style.cssText = str_image
isPaused = true;
time = 0;
}
function checkImage(imageSrc, good, bad) {
var img = new Image();
img.onload = good;
img.onerror = bad;
img.src = imageSrc;
}
function autoNextSlide() {
if (isPaused) {
time++;
if (time > 4) {
isPaused = false
};
//isPaused = true
//alert("is paused")
} else {
pictureNext();
time = 0;
isPaused = false;
};
}
</script>
</head>
<body>
<div class="bg" id="bkground">
<div class="center">
<p><input type="button" class="button" id="theButton" value="Previous" onclick="pictureBack()" style='float:left;' padding="10%"></p>
<p><input type="button" class="button" id="theButton2" value="Next" onclick="pictureNext()" style='float:right;'></p>
</div>
</div>
</body>
</html>
Use:
.bg {
/* The image used */
background-image: url("Slide1.JPG");
/* Full height */
height: 90%;
/* Center and scale the image nicely */
background-position: center;
background-repeat: no-repeat;
background-size: 100% 100%;
}
Instead of:
.bg {
/* The image used */
background-image: url("Slide1.JPG");
/* Full height */
height: 90%;
/* Center and scale the image nicely */
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
Cover makes the image cover the element in it's entirity but cuts off the image.
With 100% 100% it's makes it fit fully no matter what. It may skew the image a tad on some devices but it you aren't worried about mobile use, you should be fine.
I am currently developing a plugin for existing websites.
Its purpose is to display a sidebar with my content. To that end, the website owner creates an empty div, references my javascript file and calls my code with the ID of the empty div.
My plugin is then creating an iFrame in that empty div and loads its content. It also is responsible for styling the provided div so that it actually is a sidebar: It changes the width and height of that div and attaches it to the right edge of the screen.
So, all of that is basically working - loading my iFrame and styling the div.
The problem is that I am not satisfied with the result.
I have tried two different styles for the div:
Approach 1: float right
I used this CSS:
float: right;
height: 100%;
width: 100px;
The problem with this is that it doesn't change the total width of the rest of the page. In other words, elements on the website with a width: 100% will be shown below my sidebar.
https://jsfiddle.net/DHilgarth/mmzefm14/
Approach 2: Absolute positioning
I used this CSS:
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 100px;
This approach has the problem that my sidebar now simply overlaps the controls from the website.
https://jsfiddle.net/DHilgarth/34hmnw9h/1/
Is there a way to achieve what I want? A sidebar that basically reduces the available size of the body for all elements, except mine?
I have now chosen to actually do exactly what I asked for: I reduce the available width of the body tag.
This is not trivial because of box-sizing, padding, margin, border etc and I am sure I have missed a lot of edge cases but for now, the following logic is working for me:
If box-sizing is border-box: set the right padding of the body element to the width of my sidebar.
Otherwise, set the width of the body element to the width of the body element minus the width of the sidebar. On resize of the window, the width of the body has to be adjusted accordingly.
Code:
function initSidebar() {
loadSidebar("sidebar");
}
// This code would be loaded from a javascript file I provide
function css(element, property) {
return window.getComputedStyle(element, null).getPropertyValue(property);
}
function getSidebarWidth(sidebarElement) {
var boundingRect = sidebarElement.getBoundingClientRect();
return boundingRect.right - boundingRect.left;
}
function styleBorderBoxBody(bodyElement, sidebarElement) {
bodyElement.style.paddingRight = getSidebarWidth(sidebarElement) + "px";
}
function resizeBody(bodyElement, previousWindowWidth, previousBodyWidth) {
var currentWindowWidth = window.innerWidth;
var newBodyWidth = previousBodyWidth - previousWindowWidth + currentWindowWidth;
bodyElement.style.width = newBodyWidth + "px";
return {currentWindowWidth, newBodyWidth};
}
function styleBody(bodyElement, sidebarElement) {
var boxSizing = css(bodyElement, "box-sizing");
if(boxSizing == "content-box" || !boxSizing || boxSizing == "") {
var sidebarWidth = getSidebarWidth(sidebarElement);
var width = bodyElement.clientWidth - sidebarWidth;
bodyElement.style.width = width + "px";
sidebarElement.style.right = (-sidebarWidth) + "px";
var windowWidth = window.innerWidth;
window.addEventListener("resize", function(e) {
var newWidths = resizeBody(bodyElement, windowWidth, width);
width = newWidths.newBodyWidth;
windowWidth = newWidths.currentWindowWidth;
});
} else if(boxSizing == "border-box") {
styleBorderBoxBody(bodyElement, sidebarElement);
window.addEventListener("resize", function(e) { styleBorderBoxBody(bodyElement, sidebarElement); });
}
}
function loadSidebar(sidebarId) {
var sidebarElement = document.getElementById(sidebarId);
sidebarElement.className = "sidebar";
var bodyElement = document.getElementsByTagName("body")[0];
styleBody(bodyElement, sidebarElement);
}
// end: my code
initSidebar();
* {
margin: 0;
padding: 0;
}
html {
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
font: 14px/1.1 Helvetica, Sans-Serif;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
height: 100%;
}
#editor {
width: 100%;
height: 500px;
}
/* this class would be loaded from a CSS file I provide */
.sidebar {
border-color: green;
border-style: solid;
position: fixed;
top: 0;
right: 0;
bottom: 0;
width: 100px;
}
<div id="sidebar"></div>
<h1>Some UI from the existing website</h1>
<textarea id="editor">The text area</textarea>
I'm very new to CSS and HTML and I'm trying to create a CSS version of this:
http://i.stack.imgur.com/JNgUb.jpg
I've successfully created 4 divs with 4 different colors but this is my result:
http://i.imgur.com/ihYblSv.png
How can I scale the div to fit the entire page?
my code is:
body{
background-color: #eae1c8;
}
#bg {
transform:rotate(30deg);
-webkit-transform:rotate(30deg);
-moz-transform:rotate(30deg);
-ms-transform:rotate(30deg);
-o-transfrom:rotate(30deg);
}
#blue {
height: 25%;
background-color: #9dd2b5;
}
#green {
height: 25%;
background-color: #6aa427;
}
#yellow {
height: 25%;
background-color: #f0b747;
}
#orange {
height: 25%;
background-color: #de5b1e;
}
It fit the entire page before you rotated it.
If you want it to take up the entire page, set page body { overflow: hidden; } and then play with the sizes of your divs to fill the space. Set #bg { height: 160%; } and each color to 40% and see how that works.
Here is a Javascript Function I created with a little CSS. This is great for auto-sizing a page to fit without changing the ratio. This will resize the page on startup and when the window is resized. You can change body to the element that you want full page, and you can change the function to use a click event if you want it resized only when it is clicked. Just remove the call for the function and change the $(window).resize to $('#elementid').click
CSS:
body{
height:620px;
width:1023px;
position:absolute;
box-sizing:border-box;
transform-origin: 0 0;
-moz-transform-origin:0 0;
-o-transform-origin: 0 0;
-webkit-transform-origin: 0 0;
}
JavaScript:
var ratio;
var left;
resize();
$(window).resize(function () {resize();});
function resize()
{
ratio = window.innerHeight / $('body').innerHeight();
if (window.innerWidth / $('body').innerWidth() < ratio) {
ratio = window.innerWidth / $('body').innerWidth();
}
ratio -= .04;
$('body').css('-ms-zoom', ratio);
$('body').css('-moz-transform', 'scale(' + ratio + ')');
$('body').css('-o-transform', 'scale(' + ratio + ')');
$('body').css('-webkit-transform', 'scale(' + ratio + ')');
$('body').css('transform', 'scale(' + ratio + ')');
left = ($(window).innerWidth() - $('body').outerWidth() * ratio) / 2;
$('body').css('left', left);
}