Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Lightweight Carousel Using only HTML, CSS, JavaScript, and SVG

3.67/5 (5 votes)
6 Jul 2022CPOL8 min read 9.3K   137  
Describes the implementation of a lightweight,dynamic carousel that requires no third-party software.

1. Introduction Table of Contents

I recently decided to revise an upcoming-event carousel for an organization. The carousel appears in two places:

  • As a series of slides displayed on a TV monitor, in the organization's lounge, by a Raspberry Pi 4. Each slide is shown for 10 seconds. When all the slides have been displayed, the slideshow repeats.
  • As a carousel on the organizations website. The website carousel is a duplicate of the lounge slideshow with controls that allow pausing the slideshow, changing slide display time, and reversing the direction of the display.

The decision to implement the website carousel was driven by the fact that some of the slides have sizeable content that is not easily read in the 10 seconds allotted. Since the slides were already placed on the website for downloading to the Raspberry Pi 4, the decision to build a carousel to display the slides on the website was an easily accomplished task - or so I thought.

There appear to be as many ways to implement a carousel as there are websites that utilize them. This article describes one more that may be useful to some readers. It also describes some design decisions and some backtracking that occurred during implementation.

2. Requirements Table of Contents

The requirements levied against the website carousel were:

  • Be capable of displaying at least 30 slides (this implementation will display up to 32 slides).
  • Obtain the slides from a directory located on the website.
  • Allow the user to control the direction of slide movement (i.e., to the right or to the left).
  • Allow the user to pause and restart the display movement.
  • Allow the user to display a specific slide.
  • Allow the user to modify the time for which each slide will be displayed.

3. Design Table of Contents

The original design of the carousel used the <input type="range"...> HTML element. However, a couple of problems arose:

  • The attempt to align tick marks with the position of the range slider was, at best, "close" but not "exact." There was no way to predict where the range slider stopped as it moved from one step to the next.
  • Browser implementers differ significantly in how they interpret the W3c draft for the <input type="range"...> [^] HTML element. This means that a large amount of CSS [^] was required to make the element look consistent across browsers.

These problems resulted in a second design in which the <input type="range"...> HTML element was replaced by a set of selectable tick marks, depicted in the following design diagram.

overview

Excluding the carousel_container <div>, there are three major <div>s.

  1. The left_slide_right <div> displays a left movement control, a slide, and a right movement control. Each component is contained in its own <div>. The arrows point in the direction in which the slide movement will occur when clicked.
  2. The pause_continue_dots <div> contains the pause/continue control and the small circles representing the number of slides that will be shown (in this case 20 slides). The pause/continue control and the unfilled/filled-circles components are each contained in its own <div>. The filled circle indicates which slide is currently being displayed. By clicking on an unfilled dot, the slide that the dot represents is displayed. In this figure, the slide movement is paused and the continue arrow appears to the left of the dots. When the continue arrow is clicked, movement starts again and the continue arrow is replaced by the pause indicator (seen in this figure to left of the carousel_container <div>).
  3. The ticks_and_delay <div> contains the means by which a user can change the amount of time allotted to the display of slides. It contains selectable tick marks that allow the user to click on a tick mark to set the desired delay.

When implemented, the carousel appears as:

4. Implementation Table of Contents

The implementation described in this article uses HTML, CSS, vanilla JavaScript, and SVG. No third-party software was used.

4.1. HTML Table of Contents

left_slide_right <div>, pause_continue_dots <div>, and ticks_and_delay <div> define flex boxes. I can assure my readers that unadorned <div>s (without using flex) or <table>s were not the solution (they were tried!).

4.2. CSS Table of Contents

The flex boxes are defined in CSS.

CSS
.carousel_container,
.left_slide_right_container {
  display:flex;
  justify-content:center;
  align-items:flex-start;
  }

.left_slide_right {
  height:300px;
  display:flex;
  justify-content:center;
  align-items:center;
  }

.pause_continue_dots_container,
.time_ticks_div,
.ticks {
  display:flex;
  justify-content:center;
  align-items:center;
  }

#pause_continue_button,
#dots {
  display:flex;
  justify-content:center;
  }

The dots, both filled and unfilled, were also defined in CSS.

CSS
.dot {
  width:10px;
  height:10px;
  margin-right:2px;
  border:solid 1px Black;
  border-radius:50%;
  }

.dot:hover {
  border-color:Red;
  }

.unfilled {
  background:White;
  border-color:Black;
  }

.filled {
  background:CornflowerBlue;
  border-color:CornflowerBlue;
  }

The preceding CSS appear as internal CSS in the style element of the carousel.html document. The CSS provided in the internal CSS is specific to this Carousel implementation.

Although, parts of the CSS for the carousel appear within the internal CSS, inline CSS was also used. This form of CSS usually set values for width and height since this styling was only applicable to specific HTML elements.

Additional CSS was generated in the JavaScript found in carousel.js.

Of interest may be that a dot is only defined through CSS. Whether a specific dot is filled or unfilled is determined by the JavaScript function set_active_dot.

pause_continue_dots

The dots are separated from their left neighbors by 2 pixels; the control is separated from the dots <div> by 5 pixels. These values were chosen by experimenting to find an acceptable balance.

4.3. Javascript Table of Contents

By far, the most complex piece of code is the project's Javascript module, contained in carousel.js, and whose "namespace" is "Carousel".

Execution of the JavaScript is controlled by a JSON object.

JavaScript
<script>
  var CAROUSEL_COMPONENTS =
        {
        "slides_directory":"./Slides30",

        "timer_default_value":2,
        "timer_minimum":1,
        "timer_maximum":20,
        "timer_step":1,

        "chosen":"Red",
        "hover":"DodgerBlue",
        "normal":"LightSkyBlue",

        "debug_json":false

        }; // CAROUSEL_COMPONENTS
</script>

This JSON object should be defined in the <head> of carousel.html.

The slides that are to be displayed are expected to be in the single directory named in CAROUSEL_COMPONENTS.slides_directory. The slides themselves are named using the form

Slide1.png,Slide2.png, ....

The list of slides in the directory is recovered using XMLHttpRequest. The list returned includes more information than just the names of the slides. Each line in the XMLHttp.responseText ends with '\n' so a file list can be created by spliting the XMLHttp.responseText by that character. To extract an actual list of slides, the execution environment must be considered. This is accomplished with the following.

JavaScript
                                    // The strings returned in the
                                    // XMLHttp.responseText differ
                                    // between the localhost
                                    // environment (used in test
                                    // and debug) and the
                                    // production environment
var LOCAL_DOMAINS = &lsqb; "localhost", "127.0.0.1" &rsqb;;
var IS_LOCALHOST =
      LOCAL_DOMAINS.includes ( window.location.hostname );

The JavaScript function extract_slides_from_file_list is responsible for the generation of a list of slides. This is the function that requires change in the event that the slides are named differently than described above.

There is a limit to the number of slides that can be displayed in this implementation (limited by the number of filled/empty dots that can fit below the slide image).

JavaScript
                                    // maximum number of slides:
                                    //    width of carousel 400 px
                                    //       width of a dot  10 px
                                    //     dot right margin   2 px
                                    //      total dot width  12 px
                                    //     width of control  10 px
                                    // control right margin   5 px
                                    //  total control width  15 px
                                    // ( 400 - 15 ) / 12 = 32.08
                                    //                   ≈ 32

                                    // MORE THAN 32 SLIDES WILL BE
                                    // TRUNCATED TO 32 WITHOUT
                                    // WARNING UNLESS THE DISPLAY
                                    // IS ON LOCALHOST WHEN A
                                    // WARNING WILL BE GIVEN
var MAXIMUM_SLIDES_ALLOWED = 32;

There is also a limit to the number of tick marks that can be displayed in this implementation (limited by the number of tick marks and the legends that can fit within the carousel_container).

JavaScript
                                    // maximum number of ticks
                                    // width of carousel
                                    //            container 450 px
                                    //   width of tick mark   5 px
                                    //    tick right margin   5 px
                                    //     total tick width  10 px
                                    //     width of "delay"  50 px
                                    //   width of "seconds"  50 px
                                    //   total legend width 100 px
                                    //  ( 450 - 100 ) / 10 = 35

                                    // MORE THAN 35 TICKS WILL BE
                                    // TRUNCATED TO 35 WITHOUT
                                    // WARNING UNLESS THE DISPLAY
                                    // IS ON LOCALHOST WHEN A
                                    // WARNING WILL BE GIVEN
var MAXIMUM_TICK_MARKS_ALLOWED = 35;

Because the interaction between JavaScript and HTML is significant, a large number of document ids were required to be instantiated.

JavaScript
                                    // document ids
var carousel = document.getElementById ( "carousel" );
var dots = document.getElementById ( "dots" );
var left_side_BUT = document.getElementById ( "left_side_BUT" );
var pause_continue_button = document.getElementById (
                                        "pause_continue_button" );
var right_side_BUT = document.getElementById ( "right_side_BUT" );
var right_text  = document.getElementById ( "right_text" );
var temporary_dot = document.getElementById ( "temporary_dot" );
var ticks = document.getElementById ( "ticks" );

Javascript supplies the event handlers for all of the carousel events including:

JavaScript
dot_clicked
move_left
move_right
pause_continue_clicked
tick_clicked
tick_mouseout
tick_mouseover

There are five state variables:

JavaScript
                                    // state variables
var current_active_dot = 0;
var current_seconds = 0;
var current_tick_mark_border_color;
var moving_leftward = true;
var paused = false;

These variables either save/restore critical execution state or control how the GUI displays its content.

4.4. Scalable Vector Graphics (SVG) Table of Contents

SVG [^] was used to generate the images (other than dots) that appear in the GUI.

four_svgs

For example, the pause and continue images are generated using SVG in the JavaScript function assign_pause_or_continue_image.

JavaScript
// ******************************** assign_pause_or_continue_image

// local entry point

function assign_pause_or_continue_image ( )
  {

  pause_continue.innerHTML = "";
  if ( paused )
    {
    pause_continue.innerHTML =
      "<svg class='continue_icon'" +
      "     width='10' " +
      "     height='10'" +
      "     viewBox='0 0 10 10'" +
      "     overflow='visible'>" +
      "  <path d='M 0 0 L 10 5 L 0 10 L 0 0' " +
      "        fill='" + COMPONENTS.normal + "'" +
      "        stroke='" + COMPONENTS.normal + "'/>" +
      "</svg>";
    }
  else
    {
    pause_continue.innerHTML =
      "<svg class='pause_icon' " +
      "     width='10'" +
      "     height='10'" +
      "     viewBox='0 0 10 10'>" +
      "  <path d='M 0 0 h 4 v 10 h -4 v -10 m 6 0 h 4 v 10 h -4 v -10'" +
      "        fill='" + COMPONENTS.normal + "'" +
      "        stroke='" + COMPONENTS.normal + "'/>" +
      "</svg>";
    }

  } // assign_pause_or_continue_image

This code uses the state variable paused to determine which figure to draw. The figure outlines are created using a path. In the continue_icon, "M" moves a pen to an absolute location and "L" draws a line from the current location to an absolute location. The path is then closed. In the pause_icon, "m" moves the pen from its current position to a relative location, "h" draws a horizontal line and "v" draws a vertical line for the specified length. Because they are dynamic, these two figures are drawn with JavaScript. The left- and right-movement arrows are drawn using SVG embedded in the HTML.

HTML
                              <!-- left_side -->
<div class="left_slide_right"
     style="width:25px;" >
  <button id="left_side_BUT"
          style="background:transparent;">
    <svg version="1.1"
         width="20"
         height="23"
         xmlns="http://www.w3.org/2000/svg">
      <polygon id="left_pointing_arrow"
               points="0,11 20,0 20,23"
               fill="CornflowerBlue"
               stroke="CornflowerBlue"/>
    </svg>
  </button>
</div>
&vellip;
                              <!-- right_side -->
<div class="left_slide_right"
     style="width:25px;
            margin-left:1px;" >
  <button id="right_side_BUT"
          style="background:transparent;
                 float:left;
                 vertical-align:middle;">
    <svg version="1.1"
         width="20"
         height="23"
         xmlns="http://www.w3.org/2000/svg">
      <polygon id="right_pointing_arrow"
               points="0,0 20,11 0,23"
               fill="CornflowerBlue"
               stroke="CornflowerBlue"/>
    </svg>
  </button>
</div>

 

The figure outlines are created using a polygon which is defined as a series of points. The SVG polygon closes itself.

5. Download Table of Contents

The carousel.zip file contains the following files in the following directories (directories are bold)

Carousel_Project
    carousel.html       Project HTML
    carousel.js         Project JavaScript
    favicon.ico         Project Icon
  Slides30              Slide directory derived from Slides30.ppt
    Slide1.png
    &vellip;
    Slide30.png
Carousel_Sources
    BW_Slides30.ppt
    Initial_Design.ppt
    Miscellaneous.ppt
    Slides20.ppt
    Slides30.ppt
    Slides40.ppt
Carousel_Paper
    Carousel.html       This article
    carousel.png
    Carousel.TOC.html   This article with a TOC
    Chrome.png
    Edge.png
    Firefox.png
    Firefox_Developer.png
    four_svgs.PNG
    Internet_Explorer.png
    Opera.png
    overview.png
    pause_continue_dots.png
    range_vs_div.png
    ReturnToTOC.png
    Safari.png

For readers who intend to download the ZIP file, I suggest the following:

  • Create the directory Carousel.
  • Download the ZIP file into Carousel.
  • Extract the contents of the ZIP file into the directory Carousel. Note some ZIP file extractors want to extract the contents into a newly created directory under Carousel.
  • Using your favorite browser, open Carousel_Project/carousel.html.

Please advise me of any suggestion, comments, or criticisms. They are all equally welcome.

6. References Table of Contents

7. Conclusion Table of Contents

This article has described the implementation of a lightweight, dynamic carousel that requires no third-party software.

8. Developement Environtment Table of Contents

The Carousel Project was developed in the following environment:

Microsoft Windows 7 Professional SP 1
Microsoft Visual Studio 2008 Professional SP1
Microsoft Visual C# 2008
Microsoft .Net Framework Version 3.5 SP1

9. Supported Browsers Table of Contents

The following depicts the browsers that support this implementation of a carousel.

Chrome Edge Firefox Firefox_Developer Internet_Explorer Opera Safari
Chrome
103
Edge
91.0.625
Firefox
95.0.2
Firefox
Developer
103.0b3
Internet
Explorer 11
Opera
88.0.4412.40
Safari
5.1.7

Neither Internet Explorer nor Safari have revisions for Windows 7.

10. History Table of Contents

07/04/2022 Original article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)