I've created a list that shows partial content and collapses with a trigger. Everything is working fine except I can't manage to make this works with CSS transition when it collapses. Basically, I toggle between 2 classes and apply a height: 100%
HTML
<div class="list">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
<li>Item 9</li>
<li>Item 10</li>
<li>Item 11</li>
<li>Item 12</li>
<li>Item 13</li>
<li>Item 14</li>
</ul>
<span class="more-less"></span>
</div>
CSS
.list.expand {
height: 180px;
overflow: hidden;
}
.list.expand.open {
height: 100%;
padding-bottom: 20px;
}
JS
var list = $(".list");
$(".more-less").click(function() {
list.toggleClass("open closed");
});
I made CODEPEN to make some tests. I think this is a specific situation that needs a specific solution. I've spent hours trying snippets found here on Stackoverflow (CSS and JS) but without success.
neither CSS transition: height .5s ease; or .animate(height...) seems to work for me :/ So, any help or clue would be much appreciated :) Thanks
EDIT: I forgot a crucial information: The list content is loaded dynamically (WP), so that's why I need to set the height to "auto".
have you tried to add a transition to .list.expand?
.list.expand {
height: 180px;
overflow: hidden;
-webkit-transition: height 2s; /* For Safari 3.1 to 6.0 */
-moz-transition: height 2s;
transition: height 2s;
}
Thanks to this post, I finally found a workaround with jQuery. Probably not the best way to achieve that, but it works :p
var list = $(".list");
// Apply only if list height is taller than 100px
if (list.height() > 100) {
list.addClass("expand closed");
}
// First, set height to auto then memorize the height value in a variable,
// then set the height to 100px
list.css("height", "auto");
var listheight = list.css("height");
list.css("height", "100px");
// When click to the "more-less" trigger, toggle between "open" and "closed" class,
// then apply the correct height for each class
$(".more-less").on("click", function() {
list.toggleClass("open closed");
if (list.hasClass("open")) {
list.height(listheight);
}
if (list.hasClass("closed")) {
list.height(100);
}
});
CSS
.list.expand {
height: 180px;
overflow: hidden;
-webkit-transition: height .3s ease-in-out;
-moz-transition: height .3s ease-in-out;
transition: height .3s ease-in-out;
}
DEMO HERE on CodePen
I found a better way to achieve this, with .scrollHeight
JS
var list = $(".list");
// variable storing an integer corresponding to the scrollHeight pixel value of the element.
var fullHeight = list[0].scrollHeight+'px';
if (list.height() > 100) {
list.addClass("expand closed");
list.height(100);
}
$(".more-less").on("click", function() {
if(list.hasClass("closed")) {
list.animate({
height: fullHeight
}, 200);
} else if (list.hasClass("open")) {
list.animate({
height: "100px"
}, 200);
}
list.toggleClass("open closed");
});
CSS
.list.expand {
overflow: hidden;
}
DEMO HERE on CodePen
Related
I'm trying to turn my website to full Tailwindcss as i'm just learning it
how can i turn AFTER value in Tailwindcss ?
spanthis::before {
content: "OMANI";
animation: animate infinite 3s;
padding-left: 10px;
}
#keyframes animate {
0% {
content: "OMANI";
}
5% {
content: "COOL";
}
15% {
content: "PROFESSIONAL";
} }
UPDATE: Since v2.2 Tailwind now supports before/after
Tailwind does not support before/after pseudo-classes.
There is opened feature request about it: https://github.com/tailwindlabs/tailwindcss/discussions/2119
"Full tailwind" does not have to mean dropping CSS completely and having everything inline. You can as well combine #apply with pseudo classes.
But there is unofficial plugin for that if you really need this inline https://github.com/shimyshack/tailwindcss-pseudo-element-plugin
<ul class="inline-block">
<li class="inline-block after:inline-block after:pseudo-content-comma after:mr-1">Item 1</li>
<li class="inline-block after:inline-block after:pseudo-content-comma after:mr-1">Item 2</li>
<li class="inline-block after:inline-block after:pseudo-content-oxford-ampersand after:mr-1">Item 3</li>
<li class="inline-block">Item 4</li>
</ul>
I have a menu with a dropdown that I've centered in the page. As I've positioned it absoutely, when the dropdown is opened, the menu moves upwards (to account for the increased height due to the menu being open).
I cannot quite work out what a better way around this is? The ideal behaviour is that before the dropdown is open, the menu is perfectly centered, and then when a dropdown is opened, the top of the menu stays in place.
I'm looking to see if there is a CSS only method of maintaining the positioning. Otherwise, I'll implement some JS to position the menu on load.
var dropdown = document.getElementById("dropdown");
var show = false;
function showDropdown() {
var dropdownList = document.getElementById("dropdownList");
if (show) {
dropdownList.classList.remove("show");
show = false;
} else {
dropdownList.classList.add("show");
show = true;
}
}
dropdown.addEventListener("click", showDropdown);
.parent {
height: 100vh;
width: 100vw;
background-color: #aaa;
}
.list {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.dropdown > ul {
display: none;
}
.dropdown > ul.show {
display: block;
}
<div class="parent">
<ul class="list">
<li class="dropdown">Item One
<ul id="dropdownList">
<li>Dropdown 1</li>
<li>Dropdown 2</li>
</ul>
</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
</div>
Well the problem is you have your content aligned vertically using translate and top. I've changed this to be margin-top, but its not going to be perfect.
The automatic vertical centering of your previous method will sadly result in your content being pushed upward when it gets talked; as that is how vertical alignment works.
You basically have to manually determine where on the page it should be aligned with.
var dropdown = document.getElementById("dropdown");
var show = false;
function showDropdown() {
var dropdownList = document.getElementById("dropdownList");
if (show) {
dropdownList.classList.remove("show");
show = false;
} else {
dropdownList.classList.add("show");
show = true;
}
}
dropdown.addEventListener("click", showDropdown);
.parent {
height: 100vh;
width: 100vw;
background-color: #aaa;
}
.list {
position: absolute;
margin-top: 40vh;
}
.dropdown > ul {
display: none;
}
.dropdown > ul.show {
display: block;
}
<div class="parent">
<ul class="list">
<li class="dropdown">Item One
<ul id="dropdownList">
<li>Dropdown 1</li>
<li>Dropdown 2</li>
</ul>
</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
</div>https://stackoverflow.com/posts/66536030/edit#
I have the following HTML markup and CSS to build navigation menus:
.submenu {
max-height: 0;
overflow-y: hidden;
transition: max-height 0.3s ease-in;
}
.submenu.opened{
max-height: 200px;
}
<ul class="navigation navigation-main navigation-accordion">
<li>Dashboard</li>
<li>
Products
<ul class="submenu">
<li>All Products</li>
<li>Popular Products</li>
</ul>
</li>
</ul>
I toggle the class opened on submenu using JavaScript. The submenu slides up and down on click with the help of the transition. But I want the transitions as smooth as possible.
How can I improve the above CSS code to make it as smooth as possible, as it doesn't work well if the Product link is clicked in quick succession.
I guess everybody has another definition of smooth, but I would start here with changing the ease function from ease-in to ease-in-out and than just play with the duration of the transition. 0.3s is a bit fast in this situation, increase the duration until it fits for you. Here is an example with a duration of 1.5s:
document.querySelector('#prod').addEventListener('click', function() {
document.querySelector('.submenu').classList.toggle('opened');
}, false);
.submenu {
max-height: 0;
overflow-y: hidden;
transition: max-height 1.5s ease-in-out;
}
.submenu.opened{
max-height: 200px;
}
body {
font-size: 1.5em;
font-family: sans-serif;
line-height: 1.7
}
<ul class="navigation navigation-main navigation-accordion">
<li>Dashboard</li>
<li>
Products
<ul class="submenu">
<li>All Products</li>
<li>Popular Products</li>
</ul>
</li>
</ul>
I have a little experiment going on. I'm trying to create an onclick menu without javascript using :focus. The issue I'm having is with grandchild, which clicked it still closes the parent. I tried using the ~ selector to keep it open, but it isn't working and I don't understand as to why.
<nav id="main-menu">
<ul>
<li>Menu 1</li>
<li tabindex="0" class="onclick-item"><span>Menu 2</span>
<ul class="onclick-show-content">
<li>Sub-Menu 1</li>
<li tabindex="0" class="onclick-item"><span>Sub-Menu 2</span>
<ul class="onclick-show-content">
<li>Sub-Sub-Menu 1</li>
</ul>
</li>
</ul>
</li>
<li>Menu 3</li>
<li>Menu 4</li>
</ul>
</nav>
.onclick-item { outline: none; }
.onclick-item:focus {
pointer-events: none;
}
.onclick-item > .onclick-show-content {
overflow: hidden;
max-height: 0;
-webkit-transition: all .5s ease-in-out;
-moz-transition: all .5s ease-in-out;
transition: all .5s ease-in-out;
}
.onclick-item:focus > .onclick-show-content, .onclick-item:focus ~ .onclick-show-content {
max-height: 540px;
pointer-events: auto;
}
codepen: http://codepen.io/anon/pen/iuhtn
When you click on the grandchild, focus is taken off of its grandparent. That causes the :focus > rule to no longer apply to the grandparent.
The ~ selector doesn't work the way you're using it as there are no .onclick-show-content elements that are following siblings of .onclick-item elements. The structure that you have doesn't seem to be conducive for using ~ either, as it's parent-child-based, not sibling-based.
What I'm trying to create is a toggle that's workable without using JavaScript or jQuery. The main issue that I'm having is with getting the toggle text to switch from Open to Close when :target is applied on the #menu selector. The navigation is collapsed by default and is opened by #menu toggle.
HTML
<nav class="site-nav" id="menu">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</nav>
<section class="site-nav__toggle">
<a class="site-nav__toggle--open" href="#menu">Open</a>
<a class="site-nav__toggle--close" href="">Close</a>
</section>
CSS via SCSS
.site-nav {
border-bottom: 4px solid black;
float: left;
height: 0;
overflow: hidden;
width: 100%;
&:target {
height: 100%;
min-height: 170px;
transition: height .25s ease, min-height .25s ease;
}
}
.site-nav__toggle--open > .site-nav:target,
.site-nav__toggle--close > .site-nav {
display: none;
}
.site-nav__toggle--close > .site-nav:target,
.site-nav__toggle--open > .site-nav {
display: inline;
}
The main problem I have is that the text is not switching on the target states. Maybe a 2nd pair of eyes would help and spot the obvious if I've missed anything in this particular problem.
From W3C:
div > p
Selects all P elements where the parent is a DIV element
div + p
Selects all P elements that are placed immediately after DIV elements
I think your selectors should look like
.site-nav:target + .site-nav__toggle .site-nav__toggle--open,
.site-nav + .site-nav__toggle .site-nav__toggle--close {
display: none;
}
.site-nav:target + .site-nav__toggle .site-nav__toggle--close,
.site-nav + .site-nav__toggle .site-nav__toggle--open {
display: inline;
}
Check this codepen:
http://codepen.io/anon/pen/goAIu
Best,
Marek