How can you center a CSS arrow that reveals an accordion when clicked?

I decided to use CSS instead of Fontawesome to create the arrows for aesthetic reasons and to avoid importing an additional icon library. However, I am encountering difficulty in centering the CSS arrow properly. When it points upwards, it looks aligned near the center, but when pointing downwards, it seems to shift towards the bottom. Any suggestions on how to address this positioning issue would be greatly appreciated.

"use strict";

const panelHeader = document.querySelectorAll(".panel-header");

panelHeader.forEach(item => {
  item.addEventListener("click", event => {
    event.preventDefault();
    item.parentElement.classList.toggle("open");
    const panel = item.nextElementSibling;
    panel.style.height = panel.style.height ? null : panel.scrollHeight + "px";
  });
});
:root {
  box-sizing: border-box;
}

*,
*::before,
*::after {
  box-sizing: inherit;
}

body {
  margin: 0;
  padding: 0;
}

.accordion {
  max-width: 1200px;
  margin: 0 auto;
}

.accordion-container {
  padding: 15px;
}

h2 {
  color: #444;
  font-size: 1.75rem;
  position: relative;
  padding: 0 0 25px 0;
  margin: 15px 0 20px 0;
}

h2::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: 50px;
  height: 5px;
  background: #f79c31;
}

.panel-container > .panel + .panel {
  margin-top: 15px;
}

.panel {
  background: #f9f9f9;
  border: 1px solid #ddd;
  border-radius: 0.1875em;
}

.panel-header {
  background: #564990;
  border-color: #564990;
  border-top-left-radius: 0.1875em;
  border-top-right-radius: 0.1875em;
  position: relative;
  transition: background .25s linear;
}

.panel-header > h4 {
  margin: 0;
}

.panel-header > h4 > a {
  position: relative;
  display: block;
  color: #fff;
  font-size: 1.125rem;
  text-decoration: none;
  padding: 15px 50px 15px 15px;
}

.panel-header:hover {
  background: #443776;
}

.panel-body {
  height: 0;
  overflow: hidden;
  transition: 0.3s height 0.2s;
}

.panel-body-container {
  padding: 15px;
}

.arrow {
  position: absolute;
  top: 22px;
  right: 10px;
  font-size: 1.7rem;
  border: solid #fff;
  border-width: 0 4px 4px 0;
  display: inline-block;
  padding: 5px;
  opacity: .5;
  transform: rotate(-135deg);
  transition: transform 0.15s linear;
}

.arrow-up {

}

.panel.open .arrow {
  transform: rotate(-315deg);
  transform-origin: center center;
}
<!DOCTYPE html>
<html lang="en-US">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="accordion-faq.css">
  <title>Accordion FAQ</title>
</head>
<body>
  <section class="accordion">
    <div class="accordion-container">
      <header>
        <h2>FAQs</h2>
      </header>

      <div class="panel-container">
        <div class="panel">
          <div class="panel-header">
            <h4>
              <a href="#">First question?</a>
            </h4>
            <div class="arrow"><div class="arrow-up"></div></div>
          </div>
          <div class="panel-body">
            <div class="panel-body-container">
              <p>
                Lorem ipsum dolor sit amet, consectetur adipisicing elit.
                Accusantium animi blanditiis corporis dicta, dolor dolores
                enim facilis fuga itaque iure iusto molestiae mollitia
                natus nisi pariatur praesentium quo rerum vel.
              </p>
            </div>
          </div>
        </div> <!-- .panel -->

        <div class="panel">
          <div class="panel-header">
            <h4>
              <a href="#">Second question?</a>
            </h4>
            <div class="arrow arrow-up"></div>
          </div>
          <div class="panel-body">
            <div class="panel-body-container">
              <p>
                Lorem ipsum dolor sit amet, consectetur adipisicing elit.
                Accusantium animi blanditiis corporis dicta, dolor dolores
                enim facilis fuga itaque iure iusto molestiae mollitia
                natus nisi pariatur praesentium quo rerum vel.
              </p>
            </div>
          </div>
        </div> <!-- .panel -->
      </div> <!-- .panel-container -->
    </div> <!-- .accordion-container -->
  </section>

  <script src="accordion-faq.js"></script>
</body>
</html>

Answer №1

If your current setup is causing issues, there are a few solutions you could try:

  1. Adjust the top value in the animation class and change the animate value to all. This will smoothly animate the change in the top value without any jumping.
.arrow {
  ...
  transition: all 0.15s linear;
}

.panel.open .arrow {
  transform: rotate(-315deg);
  transform-origin: center center;
  top: 18px;
}
  1. You can also experiment with changing the transform-origin to 100% center, but be aware that this might result in a strange spinning animation.

Another option is to explore using built-in HTML arrows and rotating them if you prefer not to use a font library or an SVG icon. This approach may give you the behavior you are looking for -

Answer №2

To avoid using position: absolute, you can utilize display: flex to solve the problem:

const panelHeader = document.querySelectorAll(".panel-header");

panelHeader.forEach(item => {
  item.addEventListener("click", event => {
    event.preventDefault();
    item.parentElement.classList.toggle("open");
    const panel = item.nextElementSibling;
    panel.style.height = panel.style.height ? null : panel.scrollHeight + "px";
  });
});
:root {
  box-sizing: border-box;
}

*,
*::before,
*::after {
  box-sizing: inherit;
}

body {
  margin: 0;
  padding: 0;
}

.accordion {
  max-width: 1200px;
  margin: 0 auto;
}

.accordion-container {
  padding: 15px;
}

h2 {
  color: #444;
  font-size: 1.75rem;
  position: relative;
  padding: 0 0 25px 0;
  margin: 15px 0 20px 0;
}

h2::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: 50px;
  height: 5px;
  background: #f79c31;
}

.panel-container>.panel+.panel {
  margin-top: 15px;
}

.panel {
  background: #f9f9f9;
  border: 1px solid #ddd;
  border-radius: 0.1875em;
}

.panel-header {
  display: flex;  
  justify-content: space-between;
  align-items: center;
  background: #564990;
  border-color: #564990;
  border-top-left-radius: 0.1875em;
  border-top-right-radius: 0.1875em;
  position: relative;
  transition: background .25s linear;
}

.panel-header>h4 {
  margin: 0;
}

.panel-header>h4>a {
  position: relative;
  display: block;
  color: #fff;
  font-size: 1.125rem;
  text-decoration: none;
  padding: 15px 50px 15px 15px;
}

.panel-header:hover {
  background: #443776;
}

.panel-body {
  height: 0;
  overflow: hidden;
  transition: 0.3s height 0.2s;
}

.panel-body-container {
  padding: 15px;
}

.arrow {
  margin: 10px;
  font-size: 1.7rem;
  border: solid #fff;
  border-width: 0 4px 4px 0;
  display: inline-block;
  padding: 5px;
  opacity: .5;
  transform: rotate(-135deg);
  transition: transform 0.15s linear;
}

.arrow-up {}

.panel.open .arrow {
  margin-top: -5px;  
  transform: rotate(-315deg);
  transform-origin: center center;
}
<!DOCTYPE html>
<html lang="en-US">

<head>
  <meta charset="UTF-8>
  <meta name="viewport" content="width=device-width, initial-scale=1.0>
  <link rel="stylesheet" href="accordion-faq.css>
  <title>Accordion FAQ>
</head>

<body>
  <section class="accordion>
    <div class="accordion-container>
      <header>
        <h2>FAQs>
      </header>

      <div class="panel-container>
        <div class="panel>
          <div class="panel-header>
            <h4>
              <a href="#">First question?</a>
            </h4>
            <div class="arrow">
              <div class="arrow-up"></div>
            </div>
          </div>
          <div class="panel-body">
            <div class="panel-body-container>
              <p>
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium animi blanditiis corporis dicta, dolor dolores enim facilis fuga itaque iure iusto molestiae mollitia natus nisi pariatur praesentium quo rerum vel.
              </p>
            </div>
          </div>
        </div>
        
        <div class="panel>
          <div class="panel-header>
            <h4>
              <a href="#">Second question?</a>
            </h4>
            <div class="arrow arrow-up"></div>
          </div>
          <div class="panel-body>
            <div class="panel-body-container>
              <p>
                Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium animi blanditiis corporis dicta, dolor dolores enim facilis fuga itaque iure iusto molestiae mollitia natus nisi pariatur praesentium quo rerum vel.
              </p>
            </div>
          </div>
        </div>
      </div>
      
    </div>
    
  </section>

  <script src="accordion-faq.js></script>
</body>

</html>

Answer №3

Consider adjusting the top value within the .arrow class to top: 50% instead of using a fixed value.

Additionally, incorporate translate(0, -50%) into your transform property.

Answer №4

Utilize the top property in CSS to adjust the top position of an arrow when rotating it.
Here is a sample code snippet:

"use strict";

const panelHeader = document.querySelectorAll(".panel-header");

panelHeader.forEach(item => {
  item.addEventListener("click", event => {
    event.preventDefault();
    item.parentElement.classList.toggle("open");
    const panel = item.nextElementSibling;
    panel.style.height = panel.style.height ? null : panel.scrollHeight + "px";
  });
});
:root {
  box-sizing: border-box;
}
...
.panel.open .arrow {
  transform: rotate(-315deg);
  transform-origin: center center;
  top: 15px; //Do it!
}
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="accordion-faq.css">
  <title>Accordion FAQ</title>
</head>
<body>
  <section class="accordion">
    <div class="accordion-container">
      <header>
        <h2>FAQs</h2>
      </header>
...
</body>

For a working demonstration, visit: https://codepen.io/marchmello/pen/mdedGra

Answer №5

To achieve the desired effect on your website, make sure to implement the following CSS styles for the .panel.open .arrow element by using position: absolute and setting the top property accordingly:

"use strict";

const panelHeader = document.querySelectorAll(".panel-header");

panelHeader.forEach(item => {
  item.addEventListener("click", event => {
    event.preventDefault();
    item.parentElement.classList.toggle("open");
    const panel = item.nextElementSibling;
    panel.style.height = panel.style.height ? null : panel.scrollHeight + "px";
  });
});
:root {
  box-sizing: border-box;
}

*,
*::before,
*::after {
  box-sizing: inherit;
}

body {
  margin: 0;
  padding: 0;
}

<!-- Additional CSS styles -->

.arrow {
  position: absolute;
  top: 22px;
  right: 10px;
  font-size: 1.7rem;
  border: solid #fff;
  border-width: 0 4px 4px 0;
  display: inline-block;
  padding: 5px;
  opacity: .5;
  transform: rotate(-135deg);
  transition: transform 0.15s linear;
}


.panel.open .arrow {
  transform: rotate(-315deg);
  transform-origin: center center;
  position: absolute;
  top: 30%;
}
<!DOCTYPE html>
<html lang="en-US">
<head>
  <meta charset="UTF-8>
  <meta name="viewport" content="width=device-width, initial-scale=1.0>
  <link rel="stylesheet" href="accordion-faq.css>
  <title>Accordion FAQ</title>
</head>
<body>
  <section class="accordion>
    <div class="accordion-container>
      <header>
        <h2>FAQs</h2>
      </header>

      <div class="panel-container <
        .
.
.
.
   <!-- HTML structure remains unchanged -->
.
.
.
.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Question about transparency - HTML, CSS, and Bootstrap

I adjusted the opacity of the bootstrap card to 0.8, but now I want the table to be opaque while the rest of the card remains translucent. How can I achieve this effect? I attempted to add the style opacity : 1 to the table, but it didn't have the des ...

Blue text with the Bootstrap class ``btn-primary`` is a

When I implement twitter bootstrap into my .aspx page, the color of the text in the btn-primary appears blue instead of white. <asp:LinkButton ID="btnConfirm" runat="server" Text="Confirm" CausesValidation="true" ValidationGroup="req" CssClass="btn btn ...

After clicking the submit button, how can I eliminate the following: "config.php?username=++psw&Text=psw&submit=send?" and remain on the same page?

Whenever I hit the submit button on my form, PHP completes its task but instead of staying on the page (or simply reloading it), I am redirected to the same URL with '/config.php?username=technologies.%0D%0A++&submit = Send ". Is there a way ...

Tips for validating form data in JavaScript before invoking a PHP file

When working with a form that has an action attribute to call another PHP page, I want to ensure that one text field is not empty by validating it with JavaScript before submission. How can I accomplish this using the <input type"submit"> tag? ...

Eliminate the error notification on the login page if it corresponds to the input

I am facing an issue with my login page and the API for password validation. Even when the password matches, an error message is still being displayed. This is because I am looping through the data and need to break the loop once a match is found. How can ...

Preventing access to websites through a web application using JavaScript

I am in the process of creating a web application that enables users to create a list of websites they wish to block, preventing access from their browsers. My goal is to block websites on all browsers, but I have narrowed my focus to Chrome for now. I ha ...

Creating a carousel with three thumbnails arranged in two rows

Currently, I am using a slider for my thumbnails. If you want to check out the code for this thumbnail slider, click on this link: thumbnails slider code My goal is to display 6 thumbnails in total, with 3 thumbnails shown in each row (2 rows total). Add ...

It is not possible to place the cursor before a non-contenteditable div within a contenteditable div

Here is the layout I am working with: <div contenteditable=true> /// <div contenteditable=false>not editable</div> /// </div> One problem I'm facing is that when the non-contenteditable div is the first element on a ...

Scrolling horizontally using jQuery and CSS

I have been experimenting with creating a horizontal scrolling page that moves to the right when scrolling down and to the left when scrolling up. Here is the current code: HTML <div class="scroll-sections"> <section id=&quo ...

Removing a dynamic drop-down using Jquery can result in the removal of the entire parent

I'm attempting to create a dropdown menu that appears when a button is clicked. https://i.sstatic.net/K8om2.png Starting from the second dropdown onwards, there is a remove button that will delete the respective dropdown. The issue I'm facing ...

Using Javascript math to create a backdrop effect by drawing rectangles around multiple other rectangles

Important Note: In this discussion, the term overlay will be used interchangeably with backdrop. Currently, I am developing a guide mode where I emphasize certain elements by making them stand out against a darker semi-transparent background. The approac ...

What is the best way to design a collapsed sidebar menu?

I am trying to incorporate a side menu bar into my React application. I want it to be initially closed, only displaying icons, and then expand when clicking on one of the icons. However, I'm facing an issue where the side menu is not closing as intend ...

Ways to make a div non-clickable disappear without using JavaScript - A guide on "lightboxing" a div

I would like the score's div to pop up as a lightbox when clicking on this link : <a href="#test">TEST</a> However, I do not want it to disappear when clicking on the div itself, only on the black background! Here are my attempts: < ...

Ensure that every line of code within the button element contains all the required attributes

Struggling to get the underline on every section of my button. Attempted utilizing the -webkit-box-decoration-break property, but unfortunately it was unsuccessful. https://i.sstatic.net/jsGeQ.png It is necessary for both the initial line (New Delhi,) an ...

Learn the process of applying dynamically loaded inline and external CSS using jQuery

I have a unique situation where I am using an Ajax control within a Yahoo popup that is being loaded with jQuery. My approach involves making a simple .get request to load the HTML content. $.get(contentUrl, null, function(response) { $('# ...

creating div elements that are confined within the visible area of the browser

I'm currently attempting to append a specific number of div elements to the body without altering the width or height of the body itself. Essentially, I need the new divs to remain within the viewport. Here is the code I'm working with: divAmou ...

Angular Universal 9 disrupts the functionality of Bootstrap CSS directives

My application runs perfectly fine with npm run start. However, when I try npm run build:ssr and npm run serve:ssr, it doesn't function properly without throwing any errors. While running npm run start, there's a button with 65% opacity. The des ...

Is there a way to create an X shape by rotating two divs when I click on the container div?

I currently have this setup: code Below is the HTML code: <div id="box"> <div id="line1" class="line"></div> <div id="line2" class="line"></div> <div id="line3" class="line"></div> </div> My go ...

Tips for integrating properties into the class in jQuery

My goal is to assign properties to a class and then inherit them into individual DIV IDs. However, something seems to be off with my code. What could it be? var startItem1X = randomRange(50,100); var startItem1Y = randomRange(50,100); var startItem2X = ra ...

Converting a webpage into UTF-8 format

Can you explain the concept of encoding a webpage to me? When someone mentions that a page is encoded in UTF-8 or another format like EUC-KR, what does that signify? Does it pertain to encoding done on the server-side or client-side? Is it related to th ...