Display stars rating around rounded profile image [CSS] - html

Hi guys i'm creating rating system and i want to display the stars elements around profile image. I have profile image set to border-radius 50% which makes it rounded, but i'm struggle to set the div with the rates on the bottom of the profile image, what i'm looking for is something like this:
Example
What i have by now it's this:
body{
box-sizing: border-box;
margin: 0 auto;
background-color: #fff;
}
.avatar-inner{
width: 100px;
height: 100px;
}
.avatar{
width: 100%;
border-radius: 50%;
}
.rate-holder{
font-size: 25px;
color: #fff;
background-color: #000;
}
<div class="avatar-holder">
<div class="avatar-inner">
<img class="avatar" src="https://i.ibb.co/bmfXcFw/avatar.png" alt="" srcset="">
<div class="rate-holder">
<span>*</span>
</div>
</div>
</div>

[1]
As #RenevanderLende mentioned in comments for doing that you can use
transform:rotate() translateX();
Here's an example:
and I should mention that in provided example you have to set icon
sizes and their margins manually to match your photo-container
dimensions
// icons count
const count = 5;
// icons size in px
const size = 18;
// icons margin in px
const marign = 4;
// icons position in deg
// e.g. if you wanna position all icons at the bottom side use: 55
// e.g. if you wanna position all icons at the left side use: 120
// e.g. if you wanna position all icons at the top side use: 240
// e.g. if you wanna position all icons at the right side use: 330
const position = 0;
// get list of all photo containers
const photoContainer = document.querySelectorAll(".photo-container");
// loop through each container and generate rating stars
[...photoContainer].forEach((container) => {
// gets radius of the container
const r = container.offsetHeight / 2;
const offset = (size / Math.PI) * -1;
const ratingContainer = document.createElement("div");
ratingContainer.className = "rating-container";
const iconsHolder = document.createElement("div");
iconsHolder.className = "icons-holder";
const pos = [];
for (let i = 0; i < count; i++) {
// creates the angles array
pos.push(i * (size + offset + marign));
// creates some holders in a circularly positioned way, to hold the rating stars
const div = document.createElement("div");
div.style.position = "absolute";
div.style.display = "block";
div.style.height = `${size}px`;
div.style.width = `${size}px`;
// sets the icons positions circularly
div.style.transform = `rotate(${pos[i]}deg) translateX(${r - size + Math.abs(offset)}px)`;
// creates the star icons
const icon = document.createElement("span");
icon.className = "icon fa fa-star";
icon.style.fontSize = `${size}px`;
// arranges icons vertically(90deg)
// remove this part to see what happens
icon.style.transform = `rotate(${pos[i] * -1}deg)`;
div.append(icon);
iconsHolder.append(div);
}
// changes the all icons position
iconsHolder.style.transform = `rotate(${position}deg)`;
ratingContainer.append(iconsHolder);
container.append(ratingContainer);
});
.photo-container {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 200px;
height: 200px;
border-radius: 50%;
overflow: hidden;
}
.rating-container {
position: absolute;
inset: 0;
}
.rating-container .icons-holder {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.icons-holder>div {
cursor: pointer;
}
.icons-holder>div .icon {
color: orange;
}
.icons-holder>div .icon:hover {
color: darkgoldenrod;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<div class="photo-container">
<img style="width: 100%;" src="https://i.ibb.co/bmfXcFw/avatar.png" />
</div>
<div class="photo-container">
<img style="width: 100%;" src="https://i.ibb.co/bmfXcFw/avatar.png" />
</div>
Update:
[2]
You can also do it without using css transform (explanations are provided as comments in code.)
Example 1:
function ratingStars(root, options) {
// returns width and height of an element
const getRadius = (element) => {
return Math.round(element.offsetWidth / 2);
};
// takes radius, degrees returns x,y
const pos = (r, theta) => {
return {
// theta * (Math.PI / 180) converts radians to degrees
x: Math.round(r * Math.cos(theta * (Math.PI / 180))),
y: Math.round(r * Math.sin(theta * (Math.PI / 180))),
};
};
// default options
let op = {
count: 6,
icons_class: "rating-icons",
rotate: 0, // deg
clock_wise: true, // boolean
size: 28, // pt
icons_margin: 3.8, // px
edge_margin: 0, // px
};
// merges custom options with defaults
op = { ...op,
...options
};
// gets radius of the root element
const radius = getRadius(root); //pixels
if (radius) {
// creates the main holder of all icons
const rating = document.createElement("div");
rating.style.position = "absolute";
// moves the holder to the center of the root element
rating.style.left = `${radius - op.size / 2}px`;
rating.style.top = `${radius - op.size / 2}px`;
root.append(rating);
// generates the required degrees based on count and pushes to the degs
let degs = [];
// runs if the clock_wise is set on true
if (op.clock_wise == true)
for (let i = 0; i < op.count; i++) degs.push(Math.round(i * (op.size / Math.PI + op.icons_margin)));
// runs if the clock_wise is set on false
else
for (let i = 0; i < op.count; i++) degs.push(-Math.round(i * (op.size / Math.PI + op.icons_margin)));
// loops through the degrees and create a holder for each icon
degs.forEach((deg) => {
// creates a holder for each icon
let icon = document.createElement("div");
icon.style.position = "absolute";
icon.style.textAlign = "center";
// positions the holders in a circular way using pos() function that we created first
icon.style.left = `${pos(radius - op.size / 2 - op.edge_margin, deg + op.rotate).x}px`;
icon.style.top = `${pos(radius - op.size / 2 - op.edge_margin, deg + op.rotate).y}px`;
// appends the star icons the the holder
icon.innerHTML = `<span style="font-size: ${op.size * 0.75}pt;" class="${op.icons_class} fa fa-star"></span>`;
rating.append(icon);
});
}
}
const avatar = document.querySelector(".avatar");
ratingStars(avatar);
.avatar {
position: relative;
width: 300px;
height: 300px;
border-radius: 50%;
overflow: hidden;
background: red;
}
.rating-icons {
color: orange;
cursor: pointer;
transition: all 0.5s ease;
}
.rating-icons:hover {
color: yellow;
transform: scale(1.15) rotate(70deg);
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<div class="avatar">
<img src="https://i.pravatar.cc/300?img=11" style="height: 100%" />
</div>
Example 2:
(includes an example for each option)
function ratingStars(root, options) {
// returns width and height of an element
const getRadius = (element) => {
if (element.offsetHeight == element.offsetWidth) return Math.round(element.offsetWidth / 2);
else console.error("the given element isn't a circle");
};
// takes radius, degrees returns x,y
const pos = (r, theta) => {
return {
// theta * (Math.PI / 180) converts radians to degrees
x: Math.round(r * Math.cos(theta * (Math.PI / 180))),
y: Math.round(r * Math.sin(theta * (Math.PI / 180))),
};
};
// default options
let op = {
count: 6,
icons_class: "rating-icons",
rotate: 0, // deg
clock_wise: true, // boolean
size: 20, // pt
icons_margin: 8, // px
edge_margin: 0, // px
};
// merges custom options with defaults
op = { ...op,
...options
};
// gets radius of the root element
const radius = getRadius(root); //pixels
if (radius) {
// creates the main holder of all icons
const rating = document.createElement("div");
rating.style.position = "absolute";
// moves the holder to the center of the root element
rating.style.left = `${radius - op.size / 2}px`;
rating.style.top = `${radius - op.size / 2}px`;
root.append(rating);
// generates the required degrees based on count and pushes to the degs
let degs = [];
// runs if the clock_wise is set on true
if (op.clock_wise == true)
for (let i = 0; i < op.count; i++) degs.push(Math.round(i * (op.size / Math.PI + op.icons_margin)));
// runs if the clock_wise is set on false
else
for (let i = 0; i < op.count; i++) degs.push(-Math.round(i * (op.size / Math.PI + op.icons_margin)));
// loops through the degrees and create a holder for each icon
degs.forEach((deg) => {
// creates a holder for each icon
let icon = document.createElement("div");
icon.style.position = "absolute";
icon.style.textAlign = "center";
// positions the holders in a circular way using pos() function that we created first
icon.style.left = `${pos(radius - op.size / 2 - op.edge_margin, deg + op.rotate).x}px`;
icon.style.top = `${pos(radius - op.size / 2 - op.edge_margin, deg + op.rotate).y}px`;
// appends the star icons the the holder
icon.innerHTML = `<span style="font-size: ${op.size * 0.75}pt;" class="${op.icons_class} fa fa-star"></span>`;
rating.append(icon);
});
}
}
const avatars = document.querySelectorAll(".avatar");
ratingStars(avatars[0]);
ratingStars(avatars[1], {
icons_class: 'rating-icons red'
});
ratingStars(avatars[2], {
rotate: 143
});
ratingStars(avatars[3], {
clock_wise: false
});
ratingStars(avatars[4], {
size: 28
});
ratingStars(avatars[5], {
icons_margin: 20
});
ratingStars(avatars[6], {
edge_margin: 20
});
ratingStars(avatars[7], {
count: 4,
icons_class: 'rating-icons green',
rotate: 50,
clock_wise: true,
size: 30,
icons_margin: 40,
edge_margin: 15
});
ratingStars(avatars[8], {
count: 15
});
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
background: radial-gradient(circle farthest-corner at 10% 20%, rgba(90, 92, 106, 1) 0%, rgba(32, 45, 58, 1) 81.3%);
}
.avatar {
position: relative;
width: 200px;
height: 200px;
border-radius: 50%;
overflow: hidden;
background: red;
}
.rating-icons {
color: orange;
cursor: pointer;
transition: all 0.5s ease;
}
.rating-icons:hover {
color: darkgoldenrod;
transform: scale(1.15) rotate(70deg);
}
.red {
color: red;
}
.red:hover {
color: darkred;
}
.green {
color: green;
}
.green:hover {
color: yellowgreen;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<div style="display: flex">
<div class="avatar" style="width: 300px; height: 300px;">
<img src="https://i.pravatar.cc/300?random=1" style="height: 100%" />
</div>
</div>
<div style="display: flex">
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=1" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=2" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=3" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=5" style="height: 100%" />
</div>
</div>
<div style="display: flex">
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=6" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=7" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=8" style="height: 100%" />
</div>
<div class="avatar">
<img src="https://i.pravatar.cc/300?random=4" style="height: 100%" />
</div>
</div>

Related

HTML - Resize multiple divs and their content

I am looking to create a bottom pannel with a resizable height. The top pannel consists of 2 divs with a resizable width. I was able to follow this https://htmldom.dev/create-resizable-split-views/ , but the vertical resizing is not resizing the contents of the two top divs. How can I fill the contents of the top container with the contents of the two Divs, to ensure that they resize when the bottom pannel is dragged up?
In other words, I'm looking for two top horizontally resizable pannels and one bottom pannel vertically resizable from them, while shrinking/expanding the contents during resize.
Edit: The bottom container needs to be set on all tabs and show up under all tab content on the page.
<div class="container">
<div class = "container__top">
<div class="tab-content" >
<body class="noscroll">
<div class="Tab1">
<div class="main-body">
<div class="page-wrapper">
<div class="row">
<div class="col-sm-12">
<div class="container__left">
STUFF</div>
<div class="resizer" data-direction="horizontal"></div>
<div class="container__right">
STUFF</div>
</div>
</div>
</div>
</div>
<div class="Tab2"></div>
</body>
</div>
</div>
<div class="resizer" data-direction="vertical"></div>
<div class = "container__bottom">
STUFF</div>
You could try something like this. You'll have to be explicit for a few things, like parent height and the min/max heights for top and bottom sections, but this could be a decent start. It's ugly, sorry.
edit: it's still ugly, and you'll have to fix up the tab/hide function for more tabs, but this works as intended as far as I can tell.
document.addEventListener('DOMContentLoaded', function() {
const resizable = function(resizer) {
const direction = resizer.getAttribute('data-direction') || 'horizontal';
const prevSibling = resizer.previousElementSibling;
const nextSibling = resizer.nextElementSibling;
// The current position of mouse
let x = 0;
let y = 0;
let prevSiblingHeight = 0;
let prevSiblingWidth = 0;
// Handle the mousedown event
// that's triggered when user drags the resizer
const mouseDownHandler = function(e) {
// Get the current mouse position
x = e.clientX;
y = e.clientY;
const rect = prevSibling.getBoundingClientRect();
prevSiblingHeight = rect.height;
// Attach the listeners to `document`
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
};
const mouseMoveHandler = function(e) {
// How far the mouse has been moved
const dx = e.clientX - x;
const dy = e.clientY - y;
const parentHeight = resizer.parentNode.getBoundingClientRect().height;
const h = (prevSiblingHeight + dy)
prevSibling.style.height = `${h}px`;
nextSibling.style.height = `${parentHeight - h}px`;
const cursor = 'row-resize';
resizer.style.cursor = cursor;
document.body.style.cursor = cursor;
prevSibling.style.userSelect = 'none';
prevSibling.style.pointerEvents = 'none';
nextSibling.style.userSelect = 'none';
nextSibling.style.pointerEvents = 'none';
};
const mouseUpHandler = function() {
resizer.style.removeProperty('cursor');
document.body.style.removeProperty('cursor');
prevSibling.style.removeProperty('user-select');
prevSibling.style.removeProperty('pointer-events');
nextSibling.style.removeProperty('user-select');
nextSibling.style.removeProperty('pointer-events');
// Remove the handlers of `mousemove` and `mouseup`
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
};
// Attach the handler
resizer.addEventListener('mousedown', mouseDownHandler);
};
// Query all resizers
document.querySelectorAll('.resizer').forEach(function(ele) {
resizable(ele);
});
// Query the element
const horizontalResizer = document.getElementById('dragMeHorizontal');
const leftSide = horizontalResizer.previousElementSibling;
const rightSide = horizontalResizer.nextElementSibling;
// The current position of mouse
let x = 0;
let y = 0;
let leftWidth = 0;
// Handle the mousedown event
// that's triggered when user drags the resizer
const mouseDownHandler = function(e) {
// Get the current mouse position
x = e.clientX;
y = e.clientY;
leftWidth = leftSide.getBoundingClientRect().width;
// Attach the listeners to `document`
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
};
const mouseMoveHandler = function(e) {
// How far the mouse has been moved
const dx = e.clientX - x;
const dy = e.clientY - y;
const newLeftWidth = ((leftWidth + dx) * 100) / horizontalResizer.parentNode.getBoundingClientRect().width;
leftSide.style.width = `${newLeftWidth}%`;
horizontalResizer.style.cursor = 'col-resize';
document.body.style.cursor = 'col-resize';
leftSide.style.userSelect = 'none';
leftSide.style.pointerEvents = 'none';
rightSide.style.userSelect = 'none';
rightSide.style.pointerEvents = 'none';
};
const mouseUpHandler = function() {
horizontalResizer.style.removeProperty('cursor');
document.body.style.removeProperty('cursor');
leftSide.style.removeProperty('user-select');
leftSide.style.removeProperty('pointer-events');
rightSide.style.removeProperty('user-select');
rightSide.style.removeProperty('pointer-events');
// Remove the handlers of `mousemove` and `mouseup`
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
};
// Attach the handler
horizontalResizer.addEventListener('mousedown', mouseDownHandler);
});
// Tab Changer
function changeActiveTab(tabNumber) {
const allOtherTabs = document.getElementsByClassName("tab")
const hideElements = [...allOtherTabs].filter((element, index) => index !== tabNumber)
const selectedTab = document.getElementsByClassName("tab")[tabNumber]
hideElements.forEach(element => element.classList.add("hidden"));
selectedTab.classList.remove("hidden");
}
// handle tab 1 select
document.getElementById("tab1").addEventListener('mousedown', () => {
changeActiveTab(0)
})
// handle tab 2 select
document.getElementById("tab2").addEventListener('mousedown', () => {
changeActiveTab(1)
})
// handle tab 3 select
document.getElementById("tab3").addEventListener('mousedown', () => {
changeActiveTab(2)
})
.resizer[data-direction='vertical'] {
background-color: #cbd5e0;
cursor: ns-resize;
height: 10px;
width: 100%;
}
.button__container {
margin: 6px 12px;
display: flex;
flex-direction: row;
}
.tab__internal {
max-height: 18%;
}
button {
background-color: orange;
border: none;
padding: 8px;
min-width: 150px;
margin: 1px;
border: 1px solid teal;
}
.main__container {
display: flex;
flex-direction: column;
justify-content: center;
border: 1px solid blue;
}
.sub__container {
height: 250px;
/* Misc */
}
#tab__2 {
background-color: green;
}
#tab__3 {
background-color: teal;
}
.container__top {
/* Initial height */
height: 100%;
/* Misc */
display: flex;
flex-direction: row;
background-color: green;
}
.hidden {
display: none;
}
.tabs__container {
background-color: blue;
height: 100px;
max-height: calc(100% - 100px);
min-height: 50px;
}
.tab__contents {
height: 100%;
}
.container__bottom {
/* Take the remaining height */
width: 100%;
height: 150px;
min-height: 100px;
max-height: calc(100% - 50px);
/* Misc */
display: flex;
flex-direction: column;
background-color: red;
}
.container__left {
width: 50%;
height: 100%;
/* Misc */
display: flex;
background-color: goldenrod;
}
.resizer__horizontal {
background-color: #cbd5e0;
cursor: ew-resize;
height: 100%;
width: 5px;
}
.container__right {
/* Take the remaining width */
flex: 1;
height: 100%;
/* Misc */
display: flex;
background-color: purple;
}
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML DOM - Create resizable split views</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/demo.css" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter&family=Source+Code+Pro&display=swap" />
</head>
<body>
<div class="main__container">
<h3>Main Container</h3>
<div class="button__container">
<button class="tab_selector" id="tab1">Tab 1</button>
<button class="tab_selector" id="tab2">Tab 2</button>
<button class="tab_selector" id="tab3">Tab 3</button>
</div>
</div>
<div class="sub__container">
<div class="tabs__container">
<div class="container__top tab" id="tab__1">
<div class="container__left">
<div class="tab__contents">
<div class="tab__internal">stuff</div>
<div class="tab__internal">stuff</div>
<div class="tab__internal">stuff</div>
<div class="tab__internal">stuff</div>
</div>
</div>
<div class="resizer__horizontal" id="dragMeHorizontal"></div>
<div class="container__right tab__contents">Right</div>
</div>
<div class="container__top tab hidden" id="tab__2">
<div class="tab-contents">Tab 2</div>
</div>
<div class="container__top tab hidden" id="tab__3">
<div class="tab-contents">Tab </div>
</div>
</div>
<div class="resizer" data-direction="vertical"></div>
<div class="container__bottom">
<h4>Bottom</h4>
<p>Stuff up in here.</p>
</div>
</div>
</body>
</html>

Is it possible to do a parallax effect using the img tag in html or does it have to be done by background?

I am new to working on css/html and I was trying to do parallax effect contained in some border radius but every time I try to do it using a background (url) it doesn't seem to do what I want it to, so I was wondering if it'd be possible to do it from the img tag?
You can solve your problem using JS. Check out the example below. It will work for you. Have a nice day.
$('.img-parallax').each(function() {
var $image = $(this);
var $imageParent = $(this).parent();
function parallaxImg () {
var speed = $image.data('speed');
var imageY = $imageParent.offset().top;
var winY = $(this).scrollTop();
var winH = $(this).height();
var parentH = $imageParent.innerHeight();
// The next pixel to show on screen
var winBottom = winY + winH;
// If block is shown on screen
if (winBottom > imageY && winY < imageY + parentH) {
// Number of pixels shown after block appear
var imgBottom = ((winBottom - imageY) * speed);
// Max number of pixels until block disappear
var imgTop = winH + parentH;
// Percentage between start showing until disappearing
var imgPercent = ((imgBottom / imgTop) * 100) + (50 - (speed * 50));
}
$image.css({ top: imgPercent + '%', transform: 'translate(-50%, -' + imgPercent + '%)' });
}
$(document).on({
scroll: function () {
parallaxImg();
}, ready: function () {
parallaxImg();
}
});
});
#import url(https://fonts.googleapis.com/css?family=Amatic+SC:400,700);
html,
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
font-family: "Amatic SC", cursive;
}
.block {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
font-size: 16px;
}
.block h2 {
position: relative;
display: block;
text-align: center;
margin: 0;
top: 50%;
transform: translateY(-50%);
font-size: 10vw;
color: white;
font-weight: 400;
}
.img-parallax {
width: 100vmax;
z-index: -1;
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, 0);
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="block">
<img src="https://unsplash.it/1920/1920/?image=1003" data-speed="-1" class="img-parallax">
<h2>Parallax 1</h2>
</div>
<div class="block">
<img src="https://unsplash.it/1920/1920/?image=1002" data-speed="1" class="img-parallax">
<h2>Parallax 2</h2>
</div>
<div class="block">
<img src="https://unsplash.it/1920/1920/?image=1014" data-speed="1" class="img-parallax">
<h2>Parallax 3</h2>
</div>

CSS: Make children inside parent responsive

So I am not using any CSS framework like bootstrap to get responsiveness out of the box which is why I am having trouble making responsive layout.
Please see jsbin
I essentially what to auto-resize colorful boxes based on browser window size eg that should shrink or grow automatically based on window size. Colorful boxes inside their parent should always be in horizontal row but should be able to adjust their width and height like this example.
I tried using flex-wrap: nowrap; but it didn't do the trick :(
Please note that colorful boxes are using position:absolute with parent's position being relative. I am also adding left css property to these boxes via JavaScript to change their position for the sake of sliding animation.
function Carousel(options) {
options = options || {};
// options vars
let speed = options.speed || 1; // animation speed in seconds
let width = options.width || 200;
let height = options.height || 100;
let space = options.space || 30;
// other vars
let container = document.querySelector('.carousel-container .carousel');
let slides = container.querySelectorAll('.carousel-item');
let curSlide = null;
let prevSlide = null;
let nextSlide = null;
if (areSlidesPresent()) {
setup();
}
// functions //
function setup() {
// we assume first slide to be current one as per UI requirements
//slides[0].classList.add("current");
curSlide = slides[0];
// we assume second slide to be next as per UI requirements
nextSlide = slides[1];
// we assume last slide to be prev as per UI requirements
prevSlide = slides[slides.length - 1];
// position elements horizontally
positionSlides();
}
function areSlidesPresent() {
return slides.length > 0;
}
this.getCurrentSlide = function() {
return curSlide;
}
this.getNextSlide = function() {
return nextSlide;
}
this.getPreviousSlide = function() {
return prevSlide;
}
this.setNextSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(nextSlide);
// middle ones
for (let i = 2; i < slides.length; i++) {
allSlides.push(slides[i]);
}
allSlides.push(curSlide);
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
this.setPreviousSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(prevSlide);
allSlides.push(curSlide);
// middle ones
for (let i = 1; i < slides.length - 1; i++) {
allSlides.push(slides[i]);
}
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
function positionSlides() {
curSlide.style.marginLeft = '0px';
for (let i = 0; i < slides.length; i++) {
slides[i].querySelector('.carousel-content').style.width = (width) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height) + 'px';
let elementWidth = getStyle(nextSlide, 'width');
if (i === 0) {
slides[i].style.zIndex = -10;
//slides[i].style.opacity = '1';
slides[i].querySelector('.carousel-content').style.width = (width + 50) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height + 50) + 'px';
} else {
slides[i].style.zIndex = 0;
//slides[i].style.opacity = '0.7';
}
if (i > 0) {
slides[i].style.marginLeft = (space * 2) + 'px';
elementWidth = parseInt(elementWidth, 10) + space;
}
slides[i].style.transition = speed + 's';
slides[i].style.left = (elementWidth * i) + 'px';
}
}
function getStyle(el, prop) {
return window.getComputedStyle(el, null).getPropertyValue(prop)
.replace('px', '')
.replace('em', '');
}
}
// utility
function log(text) {
console.log(text);
}
var options = {
speed: 1, // animation speed
width: 250, // slide width
height: 150, // slide height
space: 25 // space in px between slides
};
var carousel = new Carousel(options);
function selectCurrent() {
log(carousel.getCurrentSlide());
}
function selectNext() {
carousel.setNextSlide();
}
function selectPrev() {
carousel.setPreviousSlide();
}
.carousel-container {
width: auto;
height: auto;
margin: 25px;
display: flex;
align-items: center;
justify-content: center;
}
.carousel {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.carousel .carousel-item {
position: absolute;
transition: transform .5s ease-in-out;
color: #fff;
margin-left: 10px;
-webkit-box-reflect: below 10px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(70%, transparent), to(rgba(255, 255, 255, 0.2)));
}
.carousel .carousel-item:first-child .carousel-content {
opacity: 1;
}
.carousel .carousel-item .carousel-title {
font-size: 24px;
text-align: center;
}
.carousel .carousel-item .carousel-content {
font-size: 18px;
font-weight: bold;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
}
/* temp css below */
body {
background: #2C374A;
padding-top: 150px;
}
.navigation {
display: flex;
align-items: center;
justify-content: center;
margin-top: 150px;
}
.button {
color: #444;
padding: 10px;
width: 60px;
cursor: pointer;
background: #CCC;
text-align: center;
font-weight: bold;
border-radius: 5px;
border-top: 1px solid #FFF;
box-shadow: 0 5px 0 #999;
transition: box-shadow 0.1s, top 0.1s;
margin: 10px;
}
.button:hover,
.button:hover {
color: #000;
}
.button:active,
.button:active {
top: 104px;
box-shadow: 0 1px 0 #999;
}
<div class="carousel-container">
<div class="carousel">
<div class="carousel-item">
<div class="carousel-title">Make a Call</div>
<div class="carousel-content" style="background:#0E6DE8;border:10px solid #78B1FA">Slide One</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Message</div>
<div class="carousel-content" style="background:#D90080;border:10px solid #E357A9">Slide Two</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Picture</div>
<div class="carousel-content" style="background:#FEC601;border:10px solid #FFDD64">Slide Three</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Video</div>
<div class="carousel-content" style="background:#3DB365;border:10px solid #90E0AB">Slide Four</div>
</div>
</div>
</div>
<div class="navigation">
<div class="button" onclick="selectNext()">Next</div>
<div class="button" onclick="selectCurrent()">Select</div>
<div class="button" onclick="selectPrev()">Prev</div>
</div>
Problem here was:
Width was hard-coded in your JS, so if width is in px it can't be responsive.
By applying position:absolute to you carousel-item, it forced the children to get out of the box.
What I did:
Got rid of the static width and other functionalities related to width from your JS
Removed position:absolute from carousel-item
Let me know if this is what you are expecting.
function Carousel(options) {
options = options || {};
// options vars
let speed = options.speed || 1; // animation speed in seconds
// let width = options.width || 100;
let height = options.height || 100;
let space = options.space || 30;
// other vars
let container = document.querySelector('.carousel-container .carousel');
let slides = container.querySelectorAll('.carousel-item');
let curSlide = null;
let prevSlide = null;
let nextSlide = null;
if (areSlidesPresent()) {
setup();
}
// functions //
function setup() {
// we assume first slide to be current one as per UI requirements
//slides[0].classList.add("current");
curSlide = slides[0];
// we assume second slide to be next as per UI requirements
nextSlide = slides[1];
// we assume last slide to be prev as per UI requirements
prevSlide = slides[slides.length - 1];
// position elements horizontally
positionSlides();
}
function areSlidesPresent() {
return slides.length > 0;
}
this.getCurrentSlide = function() {
return curSlide;
}
this.getNextSlide = function() {
return nextSlide;
}
this.getPreviousSlide = function() {
return prevSlide;
}
this.setNextSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(nextSlide);
// middle ones
for (let i = 2; i < slides.length; i++) {
allSlides.push(slides[i]);
}
allSlides.push(curSlide);
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
this.setPreviousSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(prevSlide);
allSlides.push(curSlide);
// middle ones
for (let i = 1; i < slides.length - 1; i++) {
allSlides.push(slides[i]);
}
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
function positionSlides() {
curSlide.style.marginLeft = '0px';
for (let i = 0; i < slides.length; i++) {
// slides[i].querySelector('.carousel-content').style.width = (width) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height) + 'px';
let elementWidth = getStyle(nextSlide, 'width');
if (i === 0) {
slides[i].style.zIndex = -10;
//slides[i].style.opacity = '1';
// slides[i].querySelector('.carousel-content').style.width = (width + 50) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height + 50) + 'px';
} else {
slides[i].style.zIndex = 0;
//slides[i].style.opacity = '0.7';
}
if (i > 0) {
slides[i].style.marginLeft = (space * 2) + 'px';
// elementWidth = parseInt(elementWidth, 10) + space;
}
slides[i].style.transition = speed + 's';
// slides[i].style.left = (elementWidth * i) + 'px';
}
}
function getStyle(el, prop) {
return window.getComputedStyle(el, null).getPropertyValue(prop)
.replace('px', '')
.replace('em', '');
}
}
// utility
function log(text) {
console.log(text);
}
var options = {
speed: 1, // animation speed
width: 250, // slide width
height: 150, // slide height
space: 25 // space in px between slides
};
var carousel = new Carousel(options);
function selectCurrent() {
log(carousel.getCurrentSlide());
}
function selectNext() {
carousel.setNextSlide();
}
function selectPrev() {
carousel.setPreviousSlide();
}
.carousel-container {
height: auto;
margin: 25px;
display: flex;
}
.carousel {
flex: 1;
height: 100%;
width: 100vh;
/* overflow:hidden; */
display: flex;
align-items: center;
justify-content: center;
}
.carousel .carousel-item {
transition: transform .5s ease-in-out;
color: #fff;
flex: 1;
margin-left: 10px;
-webkit-box-reflect: below 10px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(70%, transparent), to(rgba(255, 255, 255, 0.2)));
}
.carousel .carousel-item:first-child .carousel-content {
opacity: 1;
}
.carousel .carousel-item .carousel-title {
font-size: 24px;
text-align: center;
}
.carousel .carousel-item .carousel-content {
font-size: 18px;
font-weight: bold;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
}
/* temp css below */
body {
background: #2C374A;
}
.navigation {
display: flex;
align-items: center;
justify-content: center;
}
.button {
color: #444;
padding: 10px;
width: 60px;
cursor: pointer;
background: #CCC;
text-align: center;
font-weight: bold;
border-radius: 5px;
border-top: 1px solid #FFF;
box-shadow: 0 5px 0 #999;
transition: box-shadow 0.1s, top 0.1s;
margin: 10px;
}
.button:hover,
.button:hover {
color: #000;
}
.button:active,
.button:active {
box-shadow: 0 1px 0 #999;
}
<div class="navigation">
<div class="button" onclick="selectNext()">Next</div>
<div class="button" onclick="selectCurrent()">Select</div>
<div class="button" onclick="selectPrev()">Prev</div>
</div>
<div class="carousel-container">
<div class="carousel">
<div class="carousel-item">
<div class="carousel-title">Make a Call</div>
<div class="carousel-content" style="background:#0E6DE8;border:10px solid #78B1FA">Slide One</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Message</div>
<div class="carousel-content" style="background:#D90080;border:10px solid #E357A9">Slide Two</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Picture</div>
<div class="carousel-content" style="background:#FEC601;border:10px solid #FFDD64">Slide Three</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Video</div>
<div class="carousel-content" style="background:#3DB365;border:10px solid #90E0AB">Slide Four</div>
</div>
</div>
</div>

mix-bland-mode property prevents fully 3D transforms in Google Chome

I've encountered a very strange bug in Google Chrome!
if I use mix-blend-mode property on en element then if I apply transform: translateZ(50px); to an element below it, it doesn't work!
Please see this:
function threeD_hover(params) {
// Get the elements inside to be animated ...
var el = params.parent.find(params.element),
// defining the factor to be whether concave or covex style ...
factor = 1;
if (params.convex) {
factor = -1;
}
// Set the nessecory styles
TweenMax.set(el, {
transformPerspective: params.perspective,
rotationY: 0.01,
rotationX: 0.01,
"transform-style": "preserve-3d",
"backface-visibility": " hidden"
});
// Thee core function fo each of the elements inside ...
el.each(function(index, el) {
var $this = $(this);
function core_func(e) {
// Defining the degrees ..
var ax = params.xSensitivity * (($this.offset().left + ($this.outerWidth() / 2)) - e.pageX) / 200,
ay = params.ySensitivity * (($this.offset().top + ($this.outerHeight() / 2)) - e.pageY) / 200;
// Setting the max deg amount ...
if (ax > params.maxRotateDegreeX) {
ax = params.maxRotateDegreeX;
} else if (ax < -params.maxRotateDegreeX) {
ax = -params.maxRotateDegreeX;
}
if (ay > params.maxRotateDegreeY) {
ay = params.maxRotateDegreeY;
} else if (ay < -params.maxRotateDegreeY) {
ay = -params.maxRotateDegreeY;
}
var dx = (-factor) * ax,
dy = factor * ay;
// Animating ...
TweenMax.to($this, params.movementTime, {
rotationY: dx,
rotationX: dy,
ease: params.easing
});
}
if (!params.mouseSensitiveArea) {
params.mouseSensitiveArea = params.parent;
}
// mosuse move on canvas ..
params.mouseSensitiveArea.on("mousemove", core_func);
});
}
threeD_hover({
parent: $(".section"),
element: $(".card"),
// convex: true, // if not set it is false or concave
maxRotateDegreeX: 30,
maxRotateDegreeY: 30,
xSensitivity: 5, // Min: 1 | Max: 10
ySensitivity: 10, // Min: 1 | Max: 10
perspective: 1000,
// mouseSensitiveArea: $window, // if not set it's the parent element
easing: Power4.easeOut,
movementTime: 1
});
.parent {
background-image: url("http://www.intrawallpaper.com/static/images/background-wallpapers-26_HgdHzBm.jpg");
font-family: "Playfair Display", georgia, serif;
}
.mix-blend-overlay {
mix-blend-mode: overlay;
color: #fff;
text-align: center;
}
.section {
padding: 20px 0;
display: block;
}
.card {
pointer-events: none;
padding: 20px;
background: white;
border-radius: 5px;
width: 400px;
height: 150px;
margin: auto;
transform-style: preserve-3d;
backface-visibility: hidden;
display: flex;
box-shadow: 0 0 5px rgba(0, 0, 0, .1);
position: relative;
}
.card-content {
margin: auto;
text-align: center;
transform-style: preserve-3d;
}
h1 {
transform: translateZ(100px);
}
p {
transform: translateZ(50px);
display: block;
}
p.related {
transform: translateZ(80px);
font-style: italic;
}
a {
color: #69c6b8;
pointer-events: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
<div class="section">
<div class="card">
<div class="card-content">
<h1>Just hover around</h1>
<p><small>by Ershad</small></p>
<p class="related"><strong>This has been done using TweenMax </strong></p>
</div>
</div>
</div>
<h1 class="mix-blend-overlay">Ershad</h1>
<div class="section">
<div class="card">
<div class="card-content">
<h1>Just hover around</h1>
<p><small>by Ershad</small></p>
<p class="related"><strong>This has been done using TweenMax </strong></p>
</div>
</div>
</div>
</div>
The 2 Cards on that demo have exactly the same structure, style and js function yet the latter won't work properly because and element with mix-blend-property is before it, try to remove it and it works just fine!!
How can I solve this problem?!

Is there a way to do this effect with images on hover with css?

I have a div with 40px width and 40px height, inside i have an image (or background-image: url();) with a blue facebook icon (blue "f" without background). I wan't that when i hover that div, the logo on blue turns white and the background which is transparent turn blue, using just one image with just one logo in it. Is this possible?
Here's an example with text, FIDDLE
<div>f</div>
div {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
font-family: Tahoma;
font-size: 26px;
font-weight: bold;
color: #415e9b;
cursor: pointer;
transition: all 0.3s linear;
-moz-transition: all 0.3s linear;
-webkit-transition: all 0.3s linear;
}
div:hover {
background: #415e9b;
color: #fff;
}
You did not ask for a solution using JavaScript. However, I tried using an HTML <overlay> with some JavaScript, and it seems to work just fine.
The overlay is positioned exactly above the image, and hidden at first. It is shown only while the mouse is inside the image.
The computation expects the background of the image to be transparent.
I hope it helps.
<!doctype html>
<html>
<head>
<title>Inverse Image on Hover</title>
<meta charset="utf-8">
<style>
#logoImage, #logoOverlay {
position: absolute;
top: 0;
left: 0;
}
#logoOverlay {
visibility: hidden;
}
</style>
</head>
<body>
<div id="logo">
<img id="logoImage" src="logo.png" width="40" height="40" alt="logo">
<canvas id="logoOverlay" width="40" height="40"></canvas>
</div>
<script>
window.onload = init;
function init() {
var image = document.getElementById("logoImage");
image.onmouseover = showOverlay;
var overlayCanvas = document.getElementById("logoOverlay");
overlayCanvas.onmouseout = hideOverlay;
var overlayContext = overlayCanvas.getContext("2d");
overlayContext.drawImage(image, 0, 0, overlayCanvas.width, overlayCanvas.height);
var overlayImageData = overlayContext.getImageData(0, 0, overlayCanvas.width, overlayCanvas.height);
var length = overlayImageData.data.length / 4;
for (var i = 0; i < length; i++) {
var r = overlayImageData.data[i * 4 + 0];
var g = overlayImageData.data[i * 4 + 1];
var b = overlayImageData.data[i * 4 + 2];
var a = overlayImageData.data[i * 4 + 3];
applyEffect(i, r, g, b, a, overlayImageData.data);
}
overlayContext.putImageData(overlayImageData, 0, 0);
}
function applyEffect(pos, r, g, b, a, data) {
// your computation here based on red, green, blue, alpha pixel values
if (a < 10) {
// facebook blue
data[pos * 4 + 0] = 59;
data[pos * 4 + 1] = 89;
data[pos * 4 + 2] = 152;
data[pos * 4 + 3] = 255;
}
else {
// opaque white
data[pos * 4 + 0] = 255;
data[pos * 4 + 1] = 255;
data[pos * 4 + 2] = 255;
data[pos * 4 + 3] = 255;
}
}
function showOverlay()
{
var overlay = document.getElementById("logoOverlay");
overlay.style.visibility = 'visible';
}
function hideOverlay()
{
var overlay = document.getElementById("logoOverlay");
overlay.style.visibility = 'hidden';
}
</script>
</body>
</html>