{"id":9947,"date":"2026-06-05T07:57:37","date_gmt":"2026-06-05T12:57:37","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=9947"},"modified":"2026-06-05T07:57:38","modified_gmt":"2026-06-05T12:57:38","slug":"word-rotator-with-counter-style","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/word-rotator-with-counter-style\/","title":{"rendered":"Word Rotator with @counter-style"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In <a href=\"https:\/\/frontendmasters.com\/blog\/obscuring-text-with-counter-style\/\">the last article<\/a>, we covered a few ways for generating character strings to be used for data obfuscation. We looked at the counter style <em>systems<\/em>: <code>symbolic<\/code>, <code>alphabetic<\/code>, and <code>numeric<\/code>. Now, let\u2019s get into even more uses of <code>@counter-style<\/code> and discover additional systems.<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/obscuring-text-with-counter-style\/\">Obscuring Text with @counter-style<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/word-rotator-with-counter-style\/\">Word Rotator with @counter-style<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Word Rotator<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A word rotator is an interface designed to cycle through a predefined list of words or phrases within a static sentence. It serves as a tool to create visually appealing elements such as dynamic taglines and creative banners.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This example is made with <code>@counter-style<\/code>:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_qEqZyRQ\" src=\"\/\/codepen.io\/anon\/embed\/qEqZyRQ?height=450&amp;theme-id=1&amp;slug-hash=qEqZyRQ&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed qEqZyRQ\" title=\"CodePen Embed qEqZyRQ\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">A Set of Words<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">First, let\u2019s compile a set of words that we\u2019ll be rotating. These words will be stored in the <code>symbols<\/code> descriptor of <code>@counter-style<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@counter-style<\/span> words {\n  <span class=\"hljs-selector-tag\">symbols<\/span>: <span class=\"hljs-selector-tag\">startups<\/span> <span class=\"hljs-selector-tag\">enterprises<\/span> <span class=\"hljs-selector-tag\">nonprofits<\/span> <span class=\"hljs-selector-tag\">educators<\/span> <span class=\"hljs-selector-tag\">visionaries<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Similar to an array, we can maintain a group of words through the <code>@counter-style<\/code> declaration and later access each word based on its index\/count. The system option for this is <code>cyclic<\/code>, which allows us to loop through predefined lists of symbols. It sequentially processes the provided symbols and automatically resets to the beginning of the list once the final item is reached.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@counter-style<\/span> words {\n  <span class=\"hljs-selector-tag\">system<\/span>: <span class=\"hljs-selector-tag\">cyclic<\/span>;\n  <span class=\"hljs-selector-tag\">symbols<\/span>: <span class=\"hljs-selector-tag\">startups<\/span> <span class=\"hljs-selector-tag\">enterprises<\/span> <span class=\"hljs-selector-tag\">nonprofits<\/span> <span class=\"hljs-selector-tag\">educators<\/span> <span class=\"hljs-selector-tag\">visionaries<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s illustrate how <code>cyclic<\/code> works with a list using an example:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_zxodxqx\" src=\"\/\/codepen.io\/anon\/embed\/zxodxqx?height=450&amp;theme-id=1&amp;slug-hash=zxodxqx&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed zxodxqx\" title=\"CodePen Embed zxodxqx\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Notice that by the fourth list item, the list marker has cycled back to &#8220;a&#8221;.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Index\/Count<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For an array in JavaScript, we\u2019d use a <code>for<\/code> loop to increment a number and use it as an index to fetch the array values sequentially. Similarly, in CSS, we\u2019ll increment a count, and use it to fetch the words sequentially.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To set an incrementable number, we use a registered custom property of type integer. Here\u2019s how you can define a custom property:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@property<\/span> --i {\n  <span class=\"hljs-selector-tag\">syntax<\/span>: \"&lt;<span class=\"hljs-selector-tag\">integer<\/span>&gt;\";\n  <span class=\"hljs-selector-tag\">initial-value<\/span>: 1;\n  <span class=\"hljs-selector-tag\">inherits<\/span>: <span class=\"hljs-selector-tag\">true<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Now, let\u2019s use this custom property in the word rotator.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-id\">#rotator<\/span><span class=\"hljs-selector-pseudo\">::after<\/span> {\n  <span class=\"hljs-attribute\">counter-reset<\/span>: i <span class=\"hljs-built_in\">calc<\/span>(var(--i));\n  <span class=\"hljs-attribute\">content<\/span>: <span class=\"hljs-built_in\">counter<\/span>(i, words);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><code>counter-reset<\/code> resets the counter <code>i<\/code> with the new value of <code>--i<\/code> as it increments. The count <code>--i<\/code> is wrapped in <code>calc()<\/code> so that <code>--i<\/code> is evaluated each time its value changes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>counter(i, words)<\/code> will fetch the corresponding word to the running counter\u2019s value, similar to an array, like <code>words[i]<\/code>, that fetches a word from the current index in a loop.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s set the loop now.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Loop\/Animation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The initial value of <code>--i<\/code> was declared in the <code>@property<\/code> rule. Its final value will be the total number of words plus one, so all the words are looped through, and the last in the loop is the first word in the set. If you want it to stop at the last word then <code>--i<\/code> will be the same as the total number of words.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">main<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> <span class=\"hljs-selector-id\">#rotator<\/span><span class=\"hljs-selector-pseudo\">::after<\/span> {\n  <span class=\"hljs-attribute\">--i<\/span>: <span class=\"hljs-number\">6<\/span>;\n  <span class=\"hljs-attribute\">transition<\/span>: --i <span class=\"hljs-number\">3s<\/span> linear;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In 3 seconds, <code>--i<\/code> transitions from its initial value of 1 to 6. Here\u2019s the result:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_WboEbQa\" src=\"\/\/codepen.io\/anon\/embed\/WboEbQa?height=450&amp;theme-id=1&amp;slug-hash=WboEbQa&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed WboEbQa\" title=\"CodePen Embed WboEbQa\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">To give a nice animation effect for when words change, we can incorporate keyframe animations to add a shrink and expand effect to the words at the intervals when they appear.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@keyframes<\/span> blink {\n  17%, 34%, 35%, 52%, 53%, 70%, 71%, 88% {\n    <span class=\"hljs-attribute\">transform<\/span>: <span class=\"hljs-built_in\">scale<\/span>(<span class=\"hljs-number\">0<\/span>);\n    <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">0<\/span>;\n  }\n  22%, 26%, 39%, 43%, 56%, 60%, 72%, 76% {\n    <span class=\"hljs-attribute\">transform<\/span>: <span class=\"hljs-built_in\">scale<\/span>(<span class=\"hljs-number\">1<\/span>);\n    <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">1<\/span>;\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">We don\u2019t need the blink effect for the first and last intervals, only the ones in between.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">As mentioned earlier, 6 is the final count.\n100 divided by 6 is approximately 17.\n\nThe four intervals (excluding the first and last) are roughly the following, where the words grow and shrink in the middle of these intervals:\n\n17-34 (word fully visible 22-26 )\n35-52 (word fully visible 39-43 )\n53-70 (word fully visible 56-60 )\n71-88 (word fully visible 72-76 )<\/pre>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_qEqZyRQ\" src=\"\/\/codepen.io\/anon\/embed\/qEqZyRQ?height=450&amp;theme-id=1&amp;slug-hash=qEqZyRQ&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed qEqZyRQ\" title=\"CodePen Embed qEqZyRQ\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Pseudo Random Words<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Sometimes, a loop through of random letters creates a visually appealing effect, such as a cipher text effect. As I mentioned in the previous article, <code>numeric<\/code> and <code>alphabetic<\/code> can help create a somewhat pseudo-randomness using random symbols.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@counter-style<\/span> letters {\n  <span class=\"hljs-selector-tag\">system<\/span>: <span class=\"hljs-selector-tag\">alphabetic<\/span>;\n  <span class=\"hljs-selector-tag\">symbols<\/span>: ' ' '<span class=\"hljs-selector-tag\">x<\/span>' '1' '<span class=\"hljs-selector-tag\">z<\/span>' '9' '<span class=\"hljs-selector-tag\">s<\/span>';\n}\n<span class=\"hljs-keyword\">@property<\/span> --i {\n  <span class=\"hljs-selector-tag\">syntax<\/span>: \"&lt;<span class=\"hljs-selector-tag\">integer<\/span>&gt;\";\n  <span class=\"hljs-selector-tag\">initial-value<\/span>: 1;\n  <span class=\"hljs-selector-tag\">inherits<\/span>: <span class=\"hljs-selector-tag\">true<\/span>;\n}\n<span class=\"hljs-selector-id\">#rotator<\/span><span class=\"hljs-selector-pseudo\">::after<\/span> {\n  <span class=\"hljs-attribute\">counter-reset<\/span>: i <span class=\"hljs-built_in\">calc<\/span>(var(--i));\n  <span class=\"hljs-attribute\">content<\/span>: <span class=\"hljs-built_in\">counter<\/span>(i, letters);\n\n}\n<span class=\"hljs-selector-tag\">main<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> <span class=\"hljs-selector-id\">#rotator<\/span><span class=\"hljs-selector-pseudo\">::after<\/span> {\n  <span class=\"hljs-attribute\">--i<\/span>: <span class=\"hljs-number\">300<\/span>;\n  <span class=\"hljs-attribute\">content<\/span>: <span class=\"hljs-string\">'B2B'<\/span>;\n  <span class=\"hljs-attribute\">transition<\/span>: --i <span class=\"hljs-number\">1s<\/span> linear, content <span class=\"hljs-number\">0s<\/span> <span class=\"hljs-number\">1s<\/span> allow-discrete;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_EaNvayV\" src=\"\/\/codepen.io\/anon\/embed\/EaNvayV?height=450&amp;theme-id=1&amp;slug-hash=EaNvayV&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed EaNvayV\" title=\"CodePen Embed EaNvayV\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">A higher value for <code>--i<\/code> will produce a more jumbled sequence. The final displayed word is shown with a delay time equal to the transition time (1s) for <code>--i<\/code> to go from 1 to 300. For <code>content<\/code> to keep its delay time, <code>allow-discrete<\/code> is set as the <code>transition-behaviour<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Value-Based System<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Unlike position based systems, <code>alphabetic<\/code> and <code>numeric<\/code>, the <code>additive<\/code> system is sign-value based. In the <code>additive<\/code> system, we assign a decimal value to a symbol, and when we use the system to represent a count, the result is a sequence of symbols whose values sum up to the count.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Consider this example, where we assign the glyphs for the ace, 2, and 3 of diamonds playing cards to decimal values 1, 2, and 3 using the <code>additive<\/code> system. The symbols are provided in the <code>additive-symbols<\/code> descriptor.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@counter-style<\/span> additive-style { \n  <span class=\"hljs-selector-tag\">system<\/span>: <span class=\"hljs-selector-tag\">additive<\/span>; \n  <span class=\"hljs-comment\">\/* has to be in descending order *\/<\/span>\n  <span class=\"hljs-selector-tag\">additive-symbols<\/span>: 3 '\\1<span class=\"hljs-selector-tag\">F0C3<\/span>', 2 '\\1<span class=\"hljs-selector-tag\">F0C2<\/span>', 1 '\\1<span class=\"hljs-selector-tag\">F0C1<\/span>'; \n  <span class=\"hljs-selector-tag\">suffix<\/span><span class=\"hljs-selector-pseudo\">:''<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_GgNvgqy\" src=\"\/\/codepen.io\/anon\/embed\/GgNvgqy?height=550&amp;theme-id=1&amp;slug-hash=GgNvgqy&amp;default-tab=result\" height=\"550\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed GgNvgqy\" title=\"CodePen Embed GgNvgqy\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">In the output, the count 4 is represented by the combination of 3 of diamonds (assigned value 3), and ace of diamonds (assigned value 1), totalling to a value of 4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want to rotate through glyphs based on the sum of their assigned values, using the <code>additive<\/code> system might be useful. If the count does not exceed the number of given symbols, this system behaves similarly to the <code>cyclic<\/code> system.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@counter-style<\/span> letters {\n  <span class=\"hljs-selector-tag\">system<\/span>: <span class=\"hljs-selector-tag\">additive<\/span>;\n  <span class=\"hljs-selector-tag\">additive-symbols<\/span>: 6 \"\\1<span class=\"hljs-selector-tag\">F01E<\/span>\", 5 \"\\1<span class=\"hljs-selector-tag\">F01D<\/span>\", 4 \"\\1<span class=\"hljs-selector-tag\">F01C<\/span>\", 3 \"\\1<span class=\"hljs-selector-tag\">F01B<\/span>\", 2 \"\\1<span class=\"hljs-selector-tag\">F01A<\/span>\", 1 \"\\1<span class=\"hljs-selector-tag\">F019<\/span>\";\n}\n<span class=\"hljs-keyword\">@property<\/span> --i {\n  <span class=\"hljs-selector-tag\">syntax<\/span>: \"&lt;<span class=\"hljs-selector-tag\">integer<\/span>&gt;\";\n  <span class=\"hljs-selector-tag\">initial-value<\/span>: 1;\n  <span class=\"hljs-selector-tag\">inherits<\/span>: <span class=\"hljs-selector-tag\">true<\/span>;\n}\n<span class=\"hljs-selector-id\">#rotator<\/span><span class=\"hljs-selector-pseudo\">::after<\/span> {\n  <span class=\"hljs-attribute\">counter-reset<\/span>: i <span class=\"hljs-built_in\">calc<\/span>(var(--i));\n  <span class=\"hljs-attribute\">content<\/span>: <span class=\"hljs-built_in\">counter<\/span>(i, letters);\n}\n<span class=\"hljs-selector-tag\">main<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> <span class=\"hljs-selector-id\">#rotator<\/span><span class=\"hljs-selector-pseudo\">::after<\/span> {\n  <span class=\"hljs-attribute\">--i<\/span>: <span class=\"hljs-number\">6<\/span>;\n  <span class=\"hljs-attribute\">transition<\/span>: --i <span class=\"hljs-number\">1s<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_azByzmd\" src=\"\/\/codepen.io\/anon\/embed\/azByzmd?height=450&amp;theme-id=1&amp;slug-hash=azByzmd&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed azByzmd\" title=\"CodePen Embed azByzmd\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">All six mahjong tiles appear one after another.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As shown in this article and the previous one, <code>@counter-style<\/code> is useful in building sequences of characters, like numbers, letters, words, etc. These sequences can then be used to create both interesting bulleting systems and dynamic visual effects like the ones exemplified in the articles. CSS animation is responsible for generating the looping effect, allowing us to traverse through a count. This count, in turn, selects the appropriate symbol defined within the <code>@counter-style<\/code>, providing us with a mechanism to construct and rotate through sequences of symbols.<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/obscuring-text-with-counter-style\/\">Obscuring Text with @counter-style<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/word-rotator-with-counter-style\/\">Word Rotator with @counter-style<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Using @counter-style for tricky visual effects like word rotation and obfuscation.<\/p>\n","protected":false},"author":20,"featured_media":9980,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[492,7],"class_list":["post-9947","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-counter-style","tag-css"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/06\/cyclic.jpg?fit=2000%2C1200&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/9947","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=9947"}],"version-history":[{"count":6,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/9947\/revisions"}],"predecessor-version":[{"id":9982,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/9947\/revisions\/9982"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/9980"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=9947"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=9947"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=9947"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}