josh
josh

Reputation: 123

Trying to make the accordion collapsible open slower

I'm trying to make the accordion collapsible dropdown open a little slower, right now it opens instantly. Been trying to find online material on how to accomplish this with the code I already have. Can't seem to find anything online.

Any dropdown slowness, just trying to learn how to implement the code.

.so-accordion-wrapper {
    padding-top: 2.5rem;
    overflow: visible;
    border-bottom: 1px solid #eaeaea;
    margin-left: auto;
    margin-right: auto;
    position: relative;
    max-width: 820px;
}

.so-tab {
    position: relative;
    width: 100%;
    border-top: 1px solid #eaeaea;
    overflow: hidden;
    padding-left: 20px;
    padding-right: 20px;
}

.so-tab label {
    position: relative;
    display: block;
    padding: 0 25px 0 0;
    margin-bottom: 15px;
    margin-top: 15px;
    line-height: normal;
    cursor: pointer;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    font-size: 12px;
}

.so-tab input {
    position: absolute;
    opacity: 0;
    z-index: -1;
}

.so-tab-content {
    max-height: 0;
    overflow: hidden;
    transition: max-height .35s;
}

/* :checked */
.so-tab input:checked ~ .so-tab-content {
    max-height: none;
}

/* Icon */
.so-tab label::after {
    position: absolute;
    right: 0;
    top: -5px;
    font-size: 1.5em;
    color: #959595;
    display: block;
    -webkit-transition: all 0.50s ease;
  -moz-transition: all 0.50s ease;
    -o-transition: all 0.50s ease;
    transition: all 0.50s ease;
}

.so-tab input[type=checkbox] + label::after {
    content: "+";
}

.so-tab input[type=radio] + label::after {
    content: "\25BC";
}

.so-tab input[type=checkbox]:checked + label::after {

  transform: rotate(315deg);
}

.so-tab input[type=radio]:checked + label::after {
    transform: rotateX(180deg);
}
<div class="so-accordion-wrapper">
  <div class="so-tab"><input id="so-tab-1" type="checkbox" name="tabs"> <label for="so-tab-1">INGREDIENTS</label>
    <div class="so-tab-content">
      <p>Yes</p>
    </div>
  </div>
  <div class="so-tab"><input id="so-tab-2" type="checkbox" name="tabs"> <label for="so-tab-2">PRECAUTION</label>
    <div class="so-tab-content">
      <p>No</p>
    </div>
  </div>
</div>

Upvotes: 2

Views: 2705

Answers (3)

FluffyKitten
FluffyKitten

Reputation: 14312

As you asked in a comment, here is what I mean:

Firstly, the only change you need is for to give max-height a value - "none" doesn't work.

You have already addressed the usual problem when doing a slide up/down in CSS - you cannot transition height - by using max-height which can be used for transitions. However it needs a value for the transition to work, unfortunately none won't work because the browser cannot calculate the values needed for the transition with no value.

FYI there is also no need to change the transition-timing-function (e.g. ease, ease-in-out, cubic-bezier) or add a transition to the open div (that doesn't actually do anything in your code).

The issue I mentioned is that the slide down action is happening much more quickly than the time you have specified, i.e. 0.35s - you can see it more clearly if you set it to e.g. 1s. The slide-up action takes longer as if it is taking the correct amount of time. See example:

.so-accordion-wrapper {
    padding-top: 2.5rem;
    overflow: visible;
    border-bottom: 1px solid #eaeaea;
    margin-left: auto;
    margin-right: auto;
    position: relative;
    max-width: 820px;
}

.so-tab {
    position: relative;
    width: 100%;
    border-top: 1px solid #eaeaea;
    overflow: hidden;
    padding-left: 20px;
    padding-right: 20px;
}

.so-tab label {
    position: relative;
    display: block;
    padding: 0 25px 0 0;
    margin-bottom: 15px;
    margin-top: 15px;
    line-height: normal;
    cursor: pointer;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    font-size: 12px;
}

.so-tab input {
    position: absolute;
    opacity: 0;
    z-index: -1;
}

.so-tab-content {
    max-height: 0;
    overflow: hidden;
    transition: max-height 1s;
}

/* :checked */
.so-tab input:checked ~ .so-tab-content {
    max-height: 1000px;
}

/* Icon */
.so-tab label::after {
    position: absolute;
    right: 0;
    top: -5px;
    font-size: 1.5em;
    color: #959595;
    display: block;
    -webkit-transition: all 0.50s ease;
  -moz-transition: all 0.50s ease;
    -o-transition: all 0.50s ease;
    transition: all 0.50s ease;
}

.so-tab input[type=checkbox] + label::after {
    content: "+";
}

.so-tab input[type=radio] + label::after {
    content: "\25BC";
}

.so-tab input[type=checkbox]:checked + label::after {

  transform: rotate(315deg);
}

.so-tab input[type=radio]:checked + label::after {
    transform: rotateX(180deg);
}
<div class="so-accordion-wrapper">
  <div class="so-tab"><input id="so-tab-1" type="checkbox" name="tabs"> <label for="so-tab-1">INGREDIENTS</label>
    <div class="so-tab-content">
      <p>Yes</p>
    </div>
  </div>
  <div class="so-tab"><input id="so-tab-2" type="checkbox" name="tabs"> <label for="so-tab-2">PRECAUTION</label>
    <div class="so-tab-content">
      <p>No</p>
    </div>
  </div>
</div>

The reason for this is that the time to slide down is being calculated on the max-height you have set - e.g. 1000px in the example above. So it is taking the full 1-second to slide down 1000px, but your actual div isn't that big so it appears much more quickly.

FYI the same is happening on the slide-up, but it looks slower because it takes almost the full second to reach the "top" of the 1000px that is being shown.

The ways around this are:

  • use a more appropriate max-height, e.g. if you know your div is never going to be bigger than 100px;, then set that to your max height - see the example below.
  • javascript (which should be avoided unless necessary and the above option is unacceptable to you - the more more processing you add to the client-side the slower the page loads - which is bad for both users and Google).

Example using a more appropriate max-height: max-height: 100px - you can see the slide down is now closer to the 1-second time you specified.

.so-accordion-wrapper {
    padding-top: 2.5rem;
    overflow: visible;
    border-bottom: 1px solid #eaeaea;
    margin-left: auto;
    margin-right: auto;
    position: relative;
    max-width: 820px;
}

.so-tab {
    position: relative;
    width: 100%;
    border-top: 1px solid #eaeaea;
    overflow: hidden;
    padding-left: 20px;
    padding-right: 20px;
}

.so-tab label {
    position: relative;
    display: block;
    padding: 0 25px 0 0;
    margin-bottom: 15px;
    margin-top: 15px;
    line-height: normal;
    cursor: pointer;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    font-size: 12px;
}

.so-tab input {
    position: absolute;
    opacity: 0;
    z-index: -1;
}

.so-tab-content {
    max-height: 0;
    overflow: hidden;
    transition: max-height 1s;
}

/* :checked */
.so-tab input:checked ~ .so-tab-content {
    max-height: 100px;
}

/* Icon */
.so-tab label::after {
    position: absolute;
    right: 0;
    top: -5px;
    font-size: 1.5em;
    color: #959595;
    display: block;
    -webkit-transition: all 0.50s ease;
  -moz-transition: all 0.50s ease;
    -o-transition: all 0.50s ease;
    transition: all 0.50s ease;
}

.so-tab input[type=checkbox] + label::after {
    content: "+";
}

.so-tab input[type=radio] + label::after {
    content: "\25BC";
}

.so-tab input[type=checkbox]:checked + label::after {

  transform: rotate(315deg);
}

.so-tab input[type=radio]:checked + label::after {
    transform: rotateX(180deg);
}
<div class="so-accordion-wrapper">
  <div class="so-tab"><input id="so-tab-1" type="checkbox" name="tabs"> <label for="so-tab-1">INGREDIENTS</label>
    <div class="so-tab-content">
      <p>Yes</p>
    </div>
  </div>
  <div class="so-tab"><input id="so-tab-2" type="checkbox" name="tabs"> <label for="so-tab-2">PRECAUTION</label>
    <div class="so-tab-content">
      <p>No</p>
    </div>
  </div>
</div>

In this case, it might not be a big deal as 0.35s is quite fast anyway, but this is a very important point to remember in general, as it can have a much larger affect in other situations.

Upvotes: 3

Marios Nikolaou
Marios Nikolaou

Reputation: 1336

Max-height to none is the issue here, you should give a value in pixels and play with the transition seconds.

Nothing else should change.Check my solution.

    .so-accordion-wrapper {
    padding-top: 2.5rem;
    overflow: visible;
    border-bottom: 1px solid #eaeaea;
    margin-left: auto;
    margin-right: auto;
    position: relative;
    max-width: 820px;
}

.so-tab {
    position: relative;
    width: 100%;
    border-top: 1px solid #eaeaea;
    overflow: hidden;
    padding-left: 20px;
    padding-right: 20px;
}

.so-tab label {
    position: relative;
    display: block;
    padding: 0 25px 0 0;
    margin-bottom: 15px;
    margin-top: 15px;
    line-height: normal;
    cursor: pointer;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    font-size: 12px;
}

.so-tab input {
    position: absolute;
    opacity: 0;
}

.so-tab-content {
    max-height:0px;
    overflow: hidden;
    transition: max-height .75s;  //increase the seconds for more delay
}

/* :checked */
.so-tab input:checked ~ .so-tab-content {
    max-height:100px;
}

/* Icon */
.so-tab label::after {
    position: absolute;
    right: 0;
    top: -5px;
    font-size: 1.5em;
    color: #959595;
    display: block;
    -webkit-transition: all 0.50s ease;
    -moz-transition: all 0.50s ease;
    -o-transition: all 0.50s ease;
    transition: all 0.50s ease;
}

.so-tab input[type=checkbox] + label::after {
    content: "+";
}

.so-tab input[type=radio] + label::after {
    content: "\25BC";
}

.so-tab input[type=checkbox]:checked + label::after {

  transform: rotate(315deg);
}

.so-tab input[type=radio]:checked + label::after {
    transform: rotateX(180deg);
}
    <div class="so-accordion-wrapper">
      <div class="so-tab"><input id="so-tab-1" type="checkbox" name="tabs"> <label for="so-tab-1">INGREDIENTS</label>
        <div class="so-tab-content">
          <p>Yes</p>
        </div>
      </div>
      <div class="so-tab">
        <input id="so-tab-2" type="checkbox" name="tabs"> 
        <label for="so-tab-2">PRECAUTION</label>
        <div class="so-tab-content">
          <p>No</p>
        </div>
      </div>
    </div>

Upvotes: 1

Nick van der Waal
Nick van der Waal

Reputation: 414

Your approach is correct, however css cannot create a transition from max-height: 0 to max-height: none. when using a value using pixels you should be able to pull it off, see my fiddle here with a transition:

.so-accordion-wrapper {
    padding-top: 2.5rem;
    overflow: visible;
    border-bottom: 1px solid #eaeaea;
    margin-left: auto;
    margin-right: auto;
    position: relative;
    max-width: 820px;
}

.so-tab {
    position: relative;
    width: 100%;
    border-top: 1px solid #eaeaea;
    overflow: hidden;
    padding-left: 20px;
    padding-right: 20px;
}

.so-tab label {
    position: relative;
    display: block;
    padding: 0 25px 0 0;
    margin-bottom: 15px;
    margin-top: 15px;
    line-height: normal;
    cursor: pointer;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    font-size: 12px;
}

.so-tab input {
    position: absolute;
    opacity: 0;
    z-index: -1;
}

.so-tab-content {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.5s cubic-bezier(0, 1, 0, 1);
}

/* :checked */
.so-tab input:checked ~ .so-tab-content {
    max-height: 1000px;
    transition: max-height 0.5s ease-in-out;
}

/* Icon */
.so-tab label::after {
    position: absolute;
    right: 0;
    top: -5px;
    font-size: 1.5em;
    color: #959595;
    display: block;
    -webkit-transition: all 0.50s ease;
  -moz-transition: all 0.50s ease;
    -o-transition: all 0.50s ease;
    transition: all 0.50s ease;
}

.so-tab input[type=checkbox] + label::after {
    content: "+";
}

.so-tab input[type=radio] + label::after {
    content: "\25BC";
}

.so-tab input[type=checkbox]:checked + label::after {

  transform: rotate(315deg);
}

.so-tab input[type=radio]:checked + label::after {
    transform: rotateX(180deg);
}
<div class="so-accordion-wrapper">
  <div class="so-tab"><input id="so-tab-1" type="checkbox" name="tabs"> <label for="so-tab-1">INGREDIENTS</label>
    <div class="so-tab-content">
      <p>Yes</p>
    </div>
  </div>
  <div class="so-tab"><input id="so-tab-2" type="checkbox" name="tabs"> <label for="so-tab-2">PRECAUTION</label>
    <div class="so-tab-content">
      <p>No</p>
    </div>
  </div>
</div>

Upvotes: 1

Related Questions