Fiddle (you may have to resize results pane): http://jsfiddle.net/BxVrf/1/
Objective:
Problem:
0) As you can see, I am much better at graphic design than I am at code.
1) I am trying to have the accordion tabs diagonal (currently I can get it to work cleanly with vertical divs obviously), but short of creating a huge image I can't find a resolution-independent way of doing this. Using gradients will not work as I am using box-shadow, and a transparent border will show. CSS transforms also give less than optimal results, with or without zAccordion (I have commented them out in the Fiddle).
2) I would like CSS text flows as in the bottom image. I've found CSS Text Wrapper which is less than ideal, and a Fiddle posted elsewhere on here as follows, which again, returns less than ideal results and is currently not in the Fiddle pending first problem being solved:
var element, width, height, fontSize, numberOfParagraphs, lineHeight, numberOfLines, offsetIncrement, highestValue;
element = jQuery('p.all');
width = element.width();
height = element.height();
fontSize = element.css('font-size');
numberOfParagraphs = element.length;
lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
numberOfLines = height/lineHeight*numberOfParagraphs;
offsetIncrement = 8.5;
highestValue = Math.floor(numberOfLines*offsetIncrement);
for(var index = 0; index <= numberOfLines; index++) {
element.eq(0).before('<span class="text-offset" style="width: '+highestValue+'px; float: left; height: '+lineHeight+'px; clear: both;"/>');
highestValue = highestValue-offsetIncrement;
}
If anyone can point me in the right direction, I would be eternally grateful.
You are looking for Skew not Rotate,
transform: skewX(20deg) skewY(0deg); /* W3C */
-webkit-transform: skewX(350deg) skewY(0deg); /* Safari & Chrome */
-moz-transform: skewX(350deg) skewY(0deg); /* Firefox */
-ms-transform: skewX(350deg) skewY(0deg); /* Internet Explorer */
-o-transform: skewX(350deg) skewY(0deg); /* Opera */
Here is your updated Fiddle with solution
http://jsfiddle.net/BxVrf/9/
Related
I want to center a div, with respect to the viewport on click while animating the change in position.
I tried using CSS, adding the class on Click:
card{
width:500px;
height:500px;
transition: all 4s ease-in;
}
.active-card{
top:50%;
left:50%;
transform: translate(-50%, -50%);
}
but this causes the card to first get offset by -50% and then be brought back
so I figured I would have to calculate the offset using js and translate the card by that
const handleClick = () => {
let box = noteRef.current.getBoundingClientRect()
let centerX = window.innerWidth / 2 - (box.left + box.right) / 2;
let centerY = window.innerHeight / 2 - (box.top + box.bottom) / 2;
console.log(centerX, centerY)
card.current.style.transform = `translate(${centerX}px ,${centerY}px)`;
}
I'm trying to find the x and y cord of the card and find how much I have to offset to get it to the center
Is there a better way to do this?
You can achieve this with a few lines of JS/jQuery
The following example captures the current positioning, forces elements to absolute positioning, and animates the move to vertical & horizontal center.
Note: It's not a perfect solution for all use cases; check out how "NotClickable" shifts positions. In other words, doing a css trick that transitions elements from "relative" to "absolute" or "fixed" has consequences. And for nested elements the jQuery position() method will reveal limitations you'll have to deal with.
All that said check it out...
HTML
<div class="YouMoveMe">Clickable</div>
<span>NotClickable </span><span class="YouMoveMe">Clickable too</span>
<div class="YouMoveMe">Clickable 3</div>
JS/jQUERY
window.onload=()=>{
$(".YouMoveMe")
.on({
click:e=>{
H=e.currentTarget;
H.startLeft=$(H).position().left;
H.startTop=$(H).position().top;
$(H)
.css({position:"absolute", left:H.startLeft, top:H.startTop})
.animate({left:(window.innerWidth/2) - (H.clientWidth/2), top:(window.innerHeight/2) - (H.clientHeight/2)});
}
});
}
I'm trying to make a certain image move from top of the document to it's bottom depending on the scroll percentage, for example, when you load the site, the image will be on top of the page and as the user scrolls down it'll go down little by little depending on the overall document percentage, until at 100% it's at the bottom.
I've went through lots of similar solutions on stackoverflow and other sites, but only two seemed close to being what I need.
The first works but only on one resolution which is manually adjusted in the code:
var imgscroll = document.getElementById('myimg');
window.addEventListener('scroll', function() {
var scrollposition = window.scrollY;
imgscroll.style.top = scrollposition * 0.1323 + 'vh';
}
The second is from a stackoverflow answer - located here and copied below - I think the percentage part is what I need, but couldn't make it work (the image stopped moving):
var container = document.getElementById('container');
var windowHeight = window.innerHeight;
var windowWidth = window.innerWidth;
var scrollArea = 1000 - windowHeight;
var square1 = document.getElementsByClassName('square')[0];
var square2 = document.getElementsByClassName('square')[1];
// update position of square 1 and square 2 when scroll event fires.
window.addEventListener('scroll', function() {
var scrollTop = window.pageYOffset || window.scrollTop;
var scrollPercent = scrollTop/scrollArea || 0;
square1.style.left = scrollPercent*window.innerWidth + 'px';
square2.style.left = 800 - scrollPercent*window.innerWidth*0.6 + 'px';
});
I'd appreciate any help or tips on how to reach the answer.
Personally I find the approach where you control the position of the image by using animation-play-state: paused and assigning a CSS variable to the animation-delay one of the neatest bit of scripts I ever saw on the web. Here's the pen by Chris Coyier it's based on. And a quote from his website that describes the mechanism:
A positive animation delay is where the animation waits a certain amount of time to begin. A negative animation delay starts the animation immediately, as if that amount of time has already gone by. In other words, start the animation at a state further into the animation cycle.
When the window has loaded, we first calculate the available space below the image and the amount of page overflow. The first CSS variable --maximum defines the end point of the animation. This is recalculated when the user resizes the screen. Then when scrolling, the ratio of progress is set through another CSS variable --epoch that controls the timing of the keyframe animation.
let aim = document.getElementById('image'), room, overflow;
window.addEventListener('load', setEdge);
window.addEventListener('resize', setEdge);
window.addEventListener('scroll', function() {
let ratio = (this.pageYOffset || this.scrollY)/overflow;
aim.style.setProperty('--epoch', ratio);
});
function setEdge() {
room = window.innerHeight;
overflow = document.body.scrollHeight-room;
aim.style.setProperty('--maximum', room-aim.height + 'px');
}
body {
margin: 0;
height: 700vh;
}
#image {
position: fixed;
animation-duration: 1s;
animation-timing-function: linear;
animation-play-state: paused;
animation-iteration-count: 1;
animation-fill-mode: both;
animation-name: move;
animation-delay: calc(var(--epoch) * -1s);
}
#-webkit-keyframes move {
0% {
transform: translateY(0);
}
100% {
transform: translateY(var(--maximum));
}
}
#keyframes move {
0% {
transform: translateY(0);
}
100% {
transform: translateY(var(--maximum));
}
}
<img id="image" src="https://via.placeholder.com/140x100" alt="">
For those that want to play around with it: https://jsfiddle.net/z2r40y8c/
There are two types of zoom. The 'pinch zoom' you get on mobile browsers where content disappears off the edges of the screen. And the 'page zoom' you get on desktop browsers, like when you do Ctrl +. After 'page zoom' the page is re-flowed, so with, a responsive layout you still see the whole page width.
How can I allow users to 'page zoom' on mobile devices?
I am thinking there could be a Zoom + and Zoom - button on the header bar of my site. I want this because I have a web app that the majority of users like, both on desktop and mobile browsers. But some less capable users find the site small and fiddly on some of their mobile devices. The ability to pinch zoom (which I have not disabled) is a help, but it means constant zooming in and out to navigate.
I have tried solutions involving CSS transform: scale(...) and HTML <meta name="viewport" ...> and altering these from JavaScript. But these all seem to have a 'pinch zoom' effect, not the page zoom I am after. Also transform: scale(...) causes problems with js based/pixelbased interaction types such as draggable which I use.
I have also looked at altering CSS font sizes from JavaScript. But this only works for text, not the images, <div>s etc..
Apologies for answering my own question, but after a lot of tinkering, I found a way that works for me and seems to work on most web sites, so I thought it was worth sharing:
function zoom(scale) {
document.body.style.transform = "scale(" + scale + ")";
document.body.style.transformOrigin = "top left";
document.body.style.width = (100 / scale) + "%";
document.body.style.height = (100 / scale) + "%";
};
zoom(1.25);
The trick is to scale up the body with a scale transform, but then reduce the height and width. Reducing the height and width causes it to re-flow and keep the transformed content on the screen.
I tested the above code by pasting it into the console of Chrome Firefox and IE on several popular websites. It seems to perfectly re-scale amazon.com and stackoverflow.com, but not gmail. My own web app needed the patches described below.
Fuller solution with patches for jQuery:
With the above solution (and after pinch zoom), issues occur when JavaScript tries to measure pixel positions and use them to position other elements. This is because functions like getBoundingClientRect() returns coordinates multiplied by scale. If you use jQuery .height(), .width(), offset() etc. you get the same issue; all jQuery docs says, "dimensions may be incorrect when the page is zoomed by the user".
You can fix jQuery methods like .width() so deliver values as they would be if were viewing it with scale = 1.
Edit since jQuery 3.2.0: height(), width(), etc. have been fixed and do not require the patch shown below. But offset() still needs the patch and if you use $(window).height() or width() to find the size of the view-port you will need to divide by scale.
var zoom = (function () {
var scale = 1, recurLev = 0;
function alter(fn, adj) {
var original = $.fn[fn];
$.fn[fn] = function () {
var result;
recurLev += 1;
try {
result = original.apply(this, arguments);
} finally {
recurLev -= 1;
}
if (arguments.length === 0 && recurLev === 0) {
result = adj(result);
}
return result;
};
}
function scalePos(n) { return n / scale; }
/* Not needed since jQuery 3.2.0
alter("width", scalePos);
alter("height", scalePos);
alter("outerWidth", scalePos);
alter("outerHeight", scalePos);
alter("innerWidth", scalePos);
alter("innerHeight", scalePos);
*/
alter("offset", function (o) { o.top /= scale; o.left /= scale; return o; });
return function (s) {
scale = s;
document.body.style.transform = "scale(" + scale + ")";
document.body.style.transformOrigin = "top left";
document.body.style.width = (100 / scale) + "%";
document.body.style.height = (100 / scale) + "%";
};
}());
zoom(1.25);
The only other issue I found was in code (like dragging and drawing etc) that uses positions from events like mousedown, touchstart, mousemove, touchmove etc. I found you had to scale pageX and pageY by dividing them by scale.
If you are okay with replicating a "pinch zoom", then you can use the widely supported document.body.style.zoom property.
Try running this in your console:
document.body.style.zoom = 2;
Hi you can try this
css:
div {
margin: 150px;
width: 200px;
height: 100px;
background-color: yellow;
border: 1px solid black;
border: 1px solid black;
-ms-transform: scale(2,3); /* IE 9 */
-webkit-transform: scale(2,3); /* Safari */
transform: scale(2,3); /* Standard syntax */
}
Html:
<div>
This div element is two times of its original width, and three times of its original height.
</div>
Change font size on everything? So basically, every font size you define would need to use em as its units (intstead of px for example) so that it become a fraction of the default font.
Then you can set the body's font size (in px) to change the size of all the fonts.
function zoomPage(amount) {
var currentSize = Number(window.getComputedStyle(document.body, null).getPropertyValue('font-size').match(/\d+/));
console.log(Number(currentSize), amount, (currentSize + amount));
document.body.style.fontSize = (currentSize + amount) + 'px';
}
body {
font-size: 20px;
font-family: sans-serif;
max-width: 300px;
}
#smaller {
font-size: 0.5em;
}
.noresize {
font-size: 20px;
}
<button class="noresize" onclick="zoomPage(1)">+</button><button class="noresize" onclick="zoomPage(-1)">-</button>
<h1>I am big text</h1>
<p>I am <i>smaller</i> text</p>
<p id="smaller">I am even smaller text, even though I am also a paragraph</p>
I saw this
And thought it would be cool if I can dynamically change the colors and width of the colors with JS. The problem is I can use divs, but prefer not to. I've already tried gradients, but it didn't seem to work as expected. Any ideas on how to go about this? Additionally I'm not asking you to code this for me, rather a step of help. When I use it the div way and say set it to 33%, only 33% of the gradient shows. Not the 33% that corresponds to the color.
.a{
background-image:
linear-gradient(
to right,
#fffdc2,
#009dff 15%,
#000 15%,
#000 85%,
#fffdc2 85%
);
position: fixed;
z-index: 1031;
top: 0;
height: 4px;
transition:all 1s;
}
Gradient is definitely the way to go. Use percentage positions for the colour stops.
For example, try this function:
function generateCSSGradient(colours) {
var l = colours.length, i;
for( i=0; i<l; i++) colours[i] = colours[i].join(" ");
return "linear-gradient( to right, "+colours.join(", ")+")";
}
var cols = [
["red","0%"],
["red","40%"],
["yellow","40%"], // note same percentage - this gives a crisp change
["yellow","60%"],
["green","60%"],
["green","80%"],
["blue","80%"],
["blue","100%"]
];
yourElement.style.background = generateCSSGradient(cols);
You can adjust and vary the colours however you want - add more, move them, change them, anything goes!
I'm using bxslider to have a carousel of images. The thing is though, the images it receives to display are of somewhat unpredictable sizes. The container size is 243x243. And we know that no image will have a side smaller than 243. So...I'd like to center the image in the container. And either zoom in until the shorter of the two dimensions (L vs W) fills the container at 243, and the longer dimension overflow is hidden.
For the images I'm working with, doing this will be perfect for getting the important details of the picture in the frame.
But I'm having trouble...
I've tried the following to center the picture in the frame:
jQuery(".bx-container").each(function() {
var img_w = jQuery(this).children("img").width();
var img_h = jQuery(this).children("img").height();
var pos_top = (img_h - containerHeight) / 2;
var pos_left = (img_w - containerWidth) / 2;
var pos_top = (243 - img_h) / 2;
var pos_left = (243 - img_w) / 2;
jQuery(this).children("img").css({
'top' : pos_top + 'px',
'left' : pos_left + 'px'
});
});
And I've tried this to position not square images into the frame:
jQuery(".bx-container").each(function(){
var refRatio = 1;
var imgH = jQuery(this).children("img").height();
var imgW = jQuery(this).children("img").width();
if ( (imgW/imgH) < refRatio ) {
jQuery(this).addClass("bx-portrait");
} else {
jQuery(this).addClass("bx-landscape");
}
});
});
I've messed with both scripts and the css but I just can't seem to get it work. It either centers but doesn't resize right. Or resizes but centers wrong. Or does both wrong.
Here's the jsfiddle: http://jsfiddle.net/vgJ9X/298/
Could someone help me out?
Thanks!
EDIT:
New jsfiddle...the portrait ones work right. The landscape images still squish. :(
http://jsfiddle.net/vgJ9X/307/
EDIT:
I THINK it has something to do with relatively positioned elements not being allowed to overlap. Trying to find a fix. If anyone knows, edit the last fiddle I posted.
jQuery(".bx-container img").each(function () {
var w = jQuery(this).width();
var h = jQuery(this).height();
if (w > h) $(this).addClass('bx-landscape');
else $(this).addClass('bx-portrait');
});
Check this Updated JSFiddle
Update
jQuery(".bx-container img").each(function () {
var w = jQuery(this).width();
var h = jQuery(this).height();
if (w > h){
$(this).addClass('bx-landscape');
var trans= -243/2;
$(this).css('-webkit-transform','translateZ('+trans+'px)');
}
else if(h > w){
$(this).addClass('bx-portrait');
var trans= -243/2;
$(this).css('-webkit-transform','translateY('+trans+'px)');
}
});
check this JSFiddle
Update of Update
Found the issue with landscape, the plugin is setting max-width:100%; overriding it with max-width:none; fixes the issue...
Update Of Updated Fiddle
Try this:
img{
position:relative;
height:100%;
width:300px;
}
Simple an clean.
Demo: http://jsfiddle.net/vgJ9X/302/
I did a couple things to your jsfiddle.
First I changed the order of your resize and center functions, so the resize comes first. This way, the smaller images get resized, then centered. I also uncommented the first portion of your code.
You also had a couple of errors in your css. There was an extra closing bracket after img style declaration. Your .bx-portrait img and .bx-landscape img declarations were set to 100%px;.
Update:
Change the css in your two .bx classes to:
.bx-portrait img {
height: 100%;
width: auto;
}
.bx-landscape img {
height: auto;
width: 100%;
}
And add a clearfix to your ul:
.bxslider:after {
content: '';
clear: both;
display: table;
padding: 0;
margin: 0;
}
The height is clipping because .bx-viewport has a set height of 243px but also has a 5px border, which makes the actual internal height 233px. You'll need to make the height 253px to account for the 10px of border. This is why they don't look centered vertically.
DEMO
Why don't you just use background images instead and center them. Here is a demo from your original code
http://jsfiddle.net/8y8df/
If you want to show the full size image, just remove the background-size:contain; from the css.