Index Advisor for Couchbase N1QL Query Statement

Couchbase N1QL query statement

Overview

Index advisor is introduced in Couchbase server 6.5 as a developer preview feature. It targets at providing secondary index recommendation to help DBAs and developers optimize Couchbase N1QL query performance. This version is rule-based, and the index candidates will be generated following the design rules specified here.

  1. Leading array index key for unnest
  2. Equality predicates
  3. IN predicates
  4. Not less than/between/not greater than predicates
  5. Less than/greater than predicates
  6. Array predicates
  7. Derived join filter as leading key for left-hand-side keyspace
  8. IS NOT NULL/MISSING/VALUED predicates
  9. Functional predicates
  10. Partial index condition

Index advisor is designed to work in two ways:

Compare The Best Email Marketing Services

Our top recommendation for most people is Constant Contact because it offers the most value of any email marketing provider. Try Constant Contact free for 60 days, no credit card is required.

Email is one of the most powerful marketing tools at your disposal. It can drive engagement, build relationships, and deliver a higher ROI than every other type of marketing campaign.

Success with your email strategy starts with finding the right email marketing service. Whether you’re starting a new list from scratch or just need an easier way to reach your audience, this guide has a solution for you.

Top 13 Best Email Marketing Platforms

Best of 2023: AWeber, Brevo, Campaigner, Constant Contact, ConvertKit, Drip, GetResponse, HubSpot, MailerLite, Moosend, Omnisend, Salesforce, and SMPT.com.

I’m confident recommending all of my top picks to different businesses in different situations. However, our research team found a handful of providers that quickly rose to the top of the list.

Of the top 13, our favorite email marketing platforms for 2023 are:

Whether you’re looking to streamline multiple marketing channels, start a new email list, sink your teeth into automation, or nurture and grow an existing list, you’ll likely find everything you need and more in one of the eight platforms above.

How to choose the best email marketing services. Quicksprout.com's methodology for reviewing email marketing services.

Keep reading to learn more about our favorite platforms as well as other top contenders for different situations.

Email Marketing Service Reviews

Constant Contact – Best Overall

  • 2 Months Free
  • Drag-and-drop email builder
  • 100+ mobile-friendly templates
  • Simple email automation
Get a 60-day free trial

Constant Contact is our recommendation for most users. Beginners will find a complete toolkit that’s easy to use, and veteran email marketers will recognize immediately how much time Constant Contact can save their team, especially when it comes to marketing automation.

Don’t take my word for it. Constant Contact lets you try the full email marketing platform risk-free for 60 days, with no credit card required.

And forget about needing to be good at designing emails. The intuitive drag-and-drop email builder allows you to easily create new emails that look good and on-brand—no coding knowledge is needed. Adding text, images, videos, coupons, polls, and events to any message is simple and straightforward.

It’s a really welcoming platform to work with. People who aren’t “techy” will quickly find themselves producing much more polished newsletters. There are more than 100 pre-built, mobile-optimized templates.

Constant Contact's template options page.
Constant contact delivers 100+ mobile-friendly templates that are easy to customize with its intuitive drag-and-drop email builder.

Automation is another key benefit of Constant Contact. A lot of the legwork can be set on autopilot. For example, you can trigger welcome messages for new subscribers and set up drip campaigns based on their actions.

How much time can you save list building with beautiful templates and simple marketing automation? Constant Contact excels as an email list service, but it’s so much more.

And as soon as you hit send, Constant Contact is recording results in real-time. You’ll see everything from open rates to click-through rates, as well as data for each individual subscriber.

This is so important–how else are you going to know which strategies are working and which need to be put on pause?

Tracking email marketing campaigns with Constant Contact
real-time analytics quickly give you all the information you need to understand your email campaign performance.

Pricing for Constant Contact’s email software is straightforward. There are three plans for you to choose from—Lite, Standard, and Premium.

Like most email marketing platforms, your rate will be based on the number of subscribers on your list. Both plans allow you to send unlimited emails.

Here’s what some of the prices look like for each plan:

Lite

  • 0 – 500 Subscribers — Starting at $12 per month
  • 501 – 1,000 Subscribers — Starting at $30 per month
  • 1,001 – 2,500 Subscribers — Starting at $50 per month
  • 2,501 – 5,000 Subscribers — Starting at $80 per month

Standard

  • 0 – 500 Subscribers — Starting at $35 per month
  • 501 – 1,000 Subscribers — Starting at $55 per month
  • 1,001 – 2,500 Subscribers — Starting at $75 per month
  • 2,501 – 5,000 Subscribers — Starting at $110 per month

Premium

  • 0 – 500 Subscribers — Starting at $80 per month
  • 501 – 1,000 Subscribers — Starting at $110 per month
  • 1,001 – 2,500 Subscribers — Starting at $150 per month
  • 2,501 – 5,000 Subscribers — Starting at $200 per month

Both plans offer pricing tiers for up to 50,000 subscribers.

For basic and professional emails, the cheaper plan will be fine. But for those of you who want to get the most out of your email campaigns, I highly recommend the Standard plan.

This plan comes with more advanced features like subject line A/B testing, dynamic content, and automated behavioral campaigns. You’ll also get access to personalized demographic data, coupons, polls, and surveys.

Learn more and sign up for a free 60-day trial at Constant Contact.

MailerLite – Best For the Essentials at an Affordable Price

  • Get started for free
  • Premium plans start at $10/mo
  • All basic email features
  • A/B testing tools
Try MailerLite for free

MailerLite offers all of the essentials with none of the frills. It’s free to use for up to 1,000 subscribers, so there’s no commitment if you’re looking to test it out.

It’s a great option for anyone who wants a straightforward email marketing service. You’re a creator who doesn’t need a ton of bells and whistles. You just need the tools to start your newsletter or manage a simple campaign.

It’s also nice for teams. Nobody is going to be intimidated by this platform, which means everyone is going to use the core features at their disposal.

The platform still offers tools for automation, landing pages, pop-ups, and surveys, so it’s not like you’re extremely limited. But even the UI for each one is fairly spartan and straightforward.

MailerLite has a drag-and-drop editor, which makes it easy for anyone to design a high-quality message. Segment your subscribers to enhance personalization and optimize your campaigns with features like A/B testing.

MailerLite AB Testing
MailerLite delivers a very simplified interface with a drag-and-drop editor and the ability to segment subscribers and optimize campaigns with A/B testing.

I’d recommend MailerLite for those of you who want simple email software at an affordable rate.

MailerLite offers four pricing plans:

Free — $0 per month

  • up to 1,000 subscribers
  • 12,000 monthly emails
  • 1 user
  • Monday-Friday email support
  • ten landing pages
  • email automation builder
  • signup forms & pop-ups

Growing Business — $10 per month

  • up to 1,000 subscribers
  • unlimited monthly emails
  • three users
  • 24/7 email support
  • unlimited templates
  • dynamic emails
  • unlimited websites & blogs

Advanced — $21 per month

  • up to 1,000 subscribers
  • unlimited monthly emails
  • unlimited users
  • Facebook integration
  • custom HTML editor
  • promotion pop-ups
  • multiple automation trigggers

There is also an Enterprise plan for businesses with over 100,000 subscribers. Pricing is by quote only.

MailerLite offers a 15% discount if you sign up for annual billing, making it one of the most affordable options on our list.

Start sending emails with MailerLite for free.

Salesforce – Best for Scaling as Your Business Grows

  • Free 30-day trial
  • Small Business plans
  • As low as $25 per month
  • Segmentation and automations
Start for free

Salesforce is a behemoth in the world of customer relationship management (CRM) systems. It has a well-earned reputation as cloud-based software that manages everything from sales and marketing to customer service and commerce for some of the biggest companies in the world. 

Yet, despite being the backbone of many enterprise-level businesses, Salesforce also recognizes that smaller companies need the same type of support on a smaller scale. Which is where Salesforce Starter comes in.

Salesforce Starter package features
Salesforce offers a great package to get even the smallest business started on the path to success.

With Salesforce Starter, even the smallest startup can have access to powerful sales, service, and email outreach tools. It doesn’t require much setup, and onboarding is a breeze with simple, built-in guides to help you every step of the way.

Once you’re up and running, you can automate your email activities and segment your customers so that the right people get the right messages at the right time. You’ll also get proven, pre-built sales process templates that your team can use to convert those email leads into deals.

The best part? As your business grows, so does Salesforce, especially when it comes to email marketing.

The Salesforce Email Studio lets you quickly build sophisticated, visually appealing messages with a simple drag-and-drop interface. You can also include interactive content, like carousels and weather reports, to keep readers engaged.

You can start from scratch or use one of the many customizable templates. It is also easy to optimize your messages so they look great no matter what device a recipient uses. And once you build the perfect email, you can save the whole thing or individual content blocks to reuse again and again.

Salesforce Email Studio landing page
Salesforce Email Studio lets you build beautiful and engaging emails with a simple drag-and-drop interface

There are also other features to help you build and execute email campaigns that deliver results, including:

  • A/B testing
  • Tracking
  • Subscriber importing
  • Folder management
  • Enhanced segmentation
  • Send logging
  • Return paths to monitor deliverability and reputation

Once you reach a size where Email Studio makes sense for your organization, you’ll have virtually unlimited power for your email marketing efforts. Until then, you can still maximize your efforts with Salesforce Starter.

Salesforce is not going to be the cheapest solution on our list. But for companies poised for rapid growth, it is an excellent solution that lets you stay with the same software through all your growth phases.

Pricing is as follows:

Small Business Solutions

  • Starter $25—includes sales, service, and email outreach tools
  • Sales Professional $75—Complete sales solution for teams
  • Service Professional $75—Complete customer service solution for teams
  • Marketing Cloud Account Engagement $1,250—Marketing automation tools for teams

All of the prices for these small business solutions are per user, per month and require an annual contract billed annually.

Marketing Cloud Engagement

  • Growth $1,250—marketing automation tools
  • Plus $2,500 per month—marketing automation plus analytics
  • Advanced $4,000 per month—advanced marketing automation and analytics
  • Premium $15,000 per month—enterprise-level features plus predictive analytics and support

All prices for these packages require an annual contract billed annually. The Growth, Plus, and Advanced packages include up to 10,000 contacts. Premium gives you up to 75,000 contacts.

Salesforce pricing can get complicated fast once you move beyond the small business packages. So it is best to contact them to discuss specific needs. 

But if you’re in the small business phase, you can try Salesforce for free for 30 days. No credit card is required, and you won’t have to install any software.

Be sure to check out our full Salesforce review for even more information.

HubSpot – Best for Automated Email Marketing

  • Start for free
  • Powerful email automation
  • Stunning email templates
  • Traffic and conversion analytics
Try HubSpot for free

HubSpot is the king of marketing automation–so it’s no surprise they offer a fantastic email marketing solution for any size business.

HubSpot’s tool allows you to quickly and easily create, personalize, and optimize your emails without the need for designers or IT.

Where the software really shines is in the automated workflows. This allows you to easily set triggers for your email subscribers and nurture the leads into customers (or whatever else you want them to do).

Think of it as a choose-your-own-adventure journey that you set for your subscribers. Depending on the specific actions they take, you can have them branch off to experience different, targeted things via email.

The email marketing service is just one tool in the Swiss Army Knife that is HubSpot. It can stand alone or be used in tandem with other offerings such as Marketing Hub and their CRM. Your email marketing only becomes stronger when coupled with those products, too.

HubSpot also has plenty of pre-made email templates to help you get the results you want. With their drag-and-drop builder, you can create great emails with no coding or development knowledge needed.

HubSpot is simple to use and allows you to customize your layout, add calls-to-action and images, and modify your content and colors to match your brand.

Use their advanced personalization tools to personalize your emails in order to boost your open and clickthrough rates with ease. You can use any information in an email subscriber’s contact records to automatically serve up the most relevant subject lines, content, links, attachments, and calls to action.

Their A/B testing tool is top-notch. Use it and dive into the in-depth analytics after you send your emails to see which performed better—and why.

Hubspot email reports
Hubspot is a behemoth in the marketing automation arena, yet still makes it easy for businesses of all sizes to master email marketing.

Use this data to determine which subject lines get the most opens and the content and calls-to-action that will earn you more sales. You can also leverage this with landing pages and signup forms to accurately get a sense of the ROI of email campaigns.

The HubSpot email tool is free for up to 2,000 email sends per month, with paid plans starting at $50/month.

Join HubSpot for free to create and send email campaigns that look professionally designed and display perfectly across any device—all by yourself.

Omnisend – Best Email and SMS Marketing Combo

  • Start for free
  • Tailor-made for ecommerce businesses
  • Pre-built automations
  • Cross-channel sales tracking
Start for free

Omnisend is a simple yet powerful marketing solution that’s perfect for ecommerce shops. The platform comes with a wide range of features for automated email and SMS messaging designed to convert leads into customers.

Conversions are achieved by going one step further than most solutions. Omnisend combines text messages, web browser push notifications, email marketing, Google Customer Match, and Facebook ad retargeting to ensure you connect with as many customers as possible.

Omnisend segmentation screen
Omnisend lets you target customers in detail with numerous segmentation options.

All of these channels allow for campaign segmentation. This means you’ll be able to target the exact customers you need for specific products and services.

Omnisend also offers pre-built automations based on actions a customer might take. For example, let’s say you send them a cart abandonment email. If they don’t open that message, Omnisend can automatically send them a cart abandonment text message.

Omnisend homepage showing example of email and SMS automation trigger
Take your marketing efforts to the next level by combining email and sms campaigns with custom triggers and flows.

Omnisend has a vast library of drag-and-drop templates to choose from. You can browse by theme as well—simplifying the process of creating gorgeous, on-brand emails.

Here’s a closer look at Omnisend’s plans and pricing. Prices are based on the number of contacts you need:

Free — $0

  • Up to 500 emails per month and reach up to 250 contacts
  • Up to 60 SMS messages per month
  • Omnisend-branded email campaigns
  • Signup forms, boxes, and pop-ups
  • Sales and performance reports

Standard — Starts at $16 per month for 500 contacts

  • Up to 6000 emails per month
  • Up to 60 SMS messages per month
  • Email campaigns
  • Signup forms, boxes, and pop-ups
  • Sales and performance reports
  • SMS campaigns and automation
  • Unlimited audience segmentation
  • 24/7 email and chat support

Pro — Starts at $59 per month for 500 contacts

  • Unlimited emails per month
  • Up to 3,933 SMS messages per month
  • Email campaigns
  • Signup forms, boxes, and pop-ups
  • Advanced reporting
  • SMS campaigns and automation
  • Unlimited audience segmentation
  • 24/7 priority email and chat support
  • Unlimited web push notifications
  • Facebook custom audiences
  • Google Customer Match

Like most email marketing platforms, the cost per month increases as your contact list scales. So all the rates above are month-to-month, and Omnisend does not offer annual contracts.

The Free plan isn’t really viable for most businesses, so most of you will be evaluating the Standard and Pro options. For low-volume SMS needs, the Standard plan will be fine. But the Pro plan is definitely better for larger contact lists and businesses that want to use SMS marketing combined with email campaigns.

Standard and Pro plans both come with a customer success manager, and the Pro plan gives you access to 24/7 priority support. Sign up now to get started for free.

Brevo (formerly Sendinblue) – Best for Growing Your Customer Base

  • Limited free forever plan
  • Unlimited contacts
  • Intuitive Marketing Automations
  • Highly customizable
Try it for free today

Brevo (formerly Sendinblue) offers everything you need to launch and track an email campaign. Add your content to their machine and watch your outreach take flight.

This is a mature platform–it’s got all of the features you expect and more. You can add live chat to your site and grab new email addresses from folks browsing your store or learning about your company.

Landing page for Brevo chat.
Give customers a personalized experience with real-time chat options on their preferred channels and manage these conversations all in one place.

There’s a lot to like. More than 40 customizable templates, simple tools to build workflows, and a built-in CRM with room for as many contacts as you like.

You can use the free forever version of Brevo and send up to 300 emails per day without paying a cent. Once you see how it drives, you’ll understand why it’s so popular.

In terms of reaching more people, Brevo has everything you need. They provide a host of lead nurturing tools to help you grow your contact list:

  • Landing pages. Create actionable and engaging web pages to collect leads for you.
  • Sign-up forms. Place forms anywhere on your website to get user information.
  • Facebook ads. Leverage the power of Facebook marketing to nurture more leads.
  • Retargeted ads. Powerful ads based on a user’s previous online interactions.

Make it as simple as possible to build that list with eye-catching forms that turn website traffic into subscribers. Brevo’s intuitive interface makes embedding a form no harder than a few clicks.

Marketing automation landing page on Brevo's site.
Brevo is a powerful platform with intuitive marketing automations, a built-in CRM, and more than 40 customizable templates.

It’s easy to see how these tools help you cultivate an audience, leads, and customer growth. And, unlike other email marketing services, Brevo can support chat and SMS if you want to drive leads on your site or by text.

The platform is available via a fantastic free plan that gives you unlimited contacts and up to 300 emails per day. That’s a pretty great deal—especially if you’re running a bootstrap startup or solo operation.

Their email builder has a beginner-friendly editor that allows you to easily create the look and feel of your email.

They currently offer four different pricing tiers:

Free — $0 per month

  • Up to 300 emails per day
  • Unlimited contacts
  • Chat
  • SMS marketing
  • Email template library

Starter — $25 per month

  • Up to 100k emails
  • No daily sending limit
  • A/B testing
  • Remove the Brevo logo

Business — $65 per month

  • Up to 1MM emails
  • Marketing automation
  • Facebook ads
  • Retargeted ads
  • Landing pages
  • Telephone support

Brevo+ — Customized pricing

  • Customized email volume
  • 20+ landing pages
  • Customer success manager
  • Access for 10+ users
  • Dedicated IP

The Starter plan should be more than enough for most small businesses and startups.

However, as your business scales, the Business plan is always a great option. That comes with even more marketing features, such as Facebook and retargeted ads, along with telephone support.

Try Brevo today. Start out for free, and upgrade when it’s time to grow.

SMTP.com – Best for High-Volume Email Marketing

  • Exceptionally high deliverability
  • Detailed reporting
  • IP Reputation management
  • Automated email address validation
Try SMTP.com today

SMTP.com offers one of the most trusted email relay services that supports email at high volume. It doesn’t matter how many hundred or million emails you need to send. Payments or purchases? Not a problem.

Dealing with email deliverability problems is the worst. You put so much time into your list, segmentation, email design, and then some IP issue grinds your machine to a halt.

With SMTP.com email relay service, you can avoid deliverability issues entirely. Kick off your campaigns with confidence.

SMTP.com home page
smtp is a great solution for high-volume email campaigns.

Think of SMTP.com as a final mile delivery service for email campaigns. Ensure the maximum number of emails reach their intended destination, track all the important metrics, and report back.

It’s not here for designing, strategizing, or project managing your email marketing. Instead, it’s a focused product that ensures your careful work is carried directly to the recipient’s inbox.

You can implement SMTP.com in a variety of ways. Teams that want a hands-off experience can use managed services, and those that want more control can implement the email relay API.

However you choose to deploy SMTP.com, the software is secure and built to scale. Integrations are minutes, not days, and support is available 24/7.

It’s a great solution for companies that send a lot of transactional emails for billing, accounts, ecommerce, and so on. These emails have to be fast in order to keep customers happy and their information secure. With SMTP.com, you know the message is going to make it safe and sound.

Pricing for SMTP.com services is broken into several packages, with custom pricing available for high-volume senders:

  • Essential: $25/month for 50,000 emails per month
  • Starter: $80/month for 100,000 emails per month
  • Growth: $300/month for 500,000 emails per month
  • Business: $500/month for 1 million emails per month

Notably, the Essential plan comes with a shared IP. All other plans have a dedicated IP. For people looking to send over 250 million emails each month, SMTP.com offers a custom high-volume plan that comes with its own dedicated IP and mail transfer agent (MTA).

Any plan may add on SMTP.com’s Reputation Defender service, which monitors and protects your IP against soft and hard bounces.

This is a very focused solution that can help email marketers put deliverability issues behind them. Get started with SMTP.com today.

Campaigner – Best for Marketing Teams

  • Autoresponders and workflows
  • Custom segmentation
  • Rich personalization tools
  • Rapid A/B Testing
Try Campaigner for Free

Campaigner is the perfect tool for a team with experience that’s outgrown lightweight, beginner-facing email marketing options.

The sophistication of this tool keeps it out of the beginner camp, but it’s not so advanced as to require a developer by any means.

You’ll be able to customize your email segmentation, personalization, and customer journeys. Capture the info you really need and capitalize on it. 

Campaigner automates a lot of the busy work, giving you more time to dive into the pre-built reports on open rates, conversion rates, and so on.

Illustration of Campaigner email marketing services
When your team outgrows your lightweight email marketing solution, consider replacing it with campaigner — the midpoint between a beginner and expert campaign management solution.

Everything from an email marketing service you would want is built into the platform. Total rookies might be overwhelmed by how much you can do, but if you’ve run some campaigns, you’ll recognize how easy it is to stay on track with Campaigner.

Deliverability is exceptionally high, even among top services, and there are plenty of tools to keep your contact lists groomed and your email in good standing. 

Send transactional emails reliably with Campaigner’s SMTP relay service. Track opens, clicks, and specific links within your email. Figure out exactly what works and compound your success.

The built-in A/B testing features let you experiment with subject lines, senders, dynamic content, send times, and more. 

Campaigner is available in several packages, but you can always contact them for a custom plan. You can also sign up for a 30-day free trial, which gives you access to the entire Campaigner platform. 

Here’s how the plans break down:

  • Starter: $59/month for up to 5,000 contacts
  • Essential: $179/month for up to 25,000 contacts
  • Advanced: $649/month for up to 100,000 contacts
  • eCommerce: $79/month for up to unlimited contacts

The Starter plan comes with a trim set of segmentation tools, autoresponders, and the drag-and-drop email editor, among other tools. Upgrading your plan gives you a higher number of contacts and more advanced email marketing features.

Off the shelf, Campaigner is going to work fine for just about any email marketing use case. It gives you the tools and visibility to find wins and fine-tune your campaigns over time. Get started with Campaigner for free today.

More Great Email Marketing Services

AWeber – Best Value For Low Subscriber Count

  • Price starts at $19 per month
  • Great for <500 subscribers
  • A/B testing and automation tools
  • 700+ pre-built templates
Get started for free

AWeber is a traditional email marketing service that’s reliable and very affordable.

Where AWeber really shines, though, is its simple pricing structure. Aweber Free is ideal for those with small lists (500 subscribers or less).

Unlike other platforms that add features and capabilities for plans at different price points, AWeber offers all of its features with every plan.

Pricing is based strictly on the number of subscribers on your list. So you’ll get the same features whether you have 20 contacts or 20,000 contacts.

Here’s an overview of the pricing tiers.

  • 0 – 500 Subscribers — $19 per month
  • 501 – 2,500 Subscribers — $29 per month
  • 2,501 – 5,000 Subscribers — $49 per month
  • 5,001 – 10,000 Subscribers — $69 per month
  • 10,001 – 25,000 Subscribers — $149 per month
AWeber homepage
Even with its affordable price point, AWeBER still provides the features you need to succeed.

With AWeber, you’ll get all of the basic features that you expect with an email marketing service:

  • 700+ pre-built templates
  • Drag-and-drop email builder
  • Email analytics
  • A/B testing
  • Sign up forms
  • Automation
  • Third-party integrations
  • Subscriber segmentation

AWeber is an industry leader in email deliverability rates. They make sure that your content is optimized to reach your subscribers’ inboxes.

You can try AWeber for free.

GetResponse – Best for Automated Lead Generation

  • Price starts at $15 per month
  • Automated sales funnels
  • 200+ email templates
  • 24/7 live chat support
Get a 30-day free trial

GetResponse is a bit more than a basic email marketing service. It’s more of an all-in-one solution that specializes in automation.

And when we say all-in-one, we mean it.

With tools and features such as audience segmentation, autoresponders, landing page builders, automated emails, advanced analytics, and even webinar software, you’ll be able to collect beaucoup leads, put them in the right workflows, and turn them into returning customers.

One standout tool that GetResponse offers is called Autofunnel. It can be used to create funnels for sales, leads, webinars, and more. It’s fully automated and very easy to use.

Funnels include things like emails, landing pages, exit popups, marketing automation, Facebook ads, and ecommerce integration. It all depends on your goals and how you want to set them up. But GetResponse provides all the tools you need to grow your subscriber list and monetize those contacts.

Once a user enters your funnel, everything is fully automated by GetResponse. It’s the perfect way to guide customers through the conversion process with multiple digital touchpoints.

GetResponse Features
GetResponse is an all-in-one solution that includes Autofunnel which takes the guesswork out of growing your subscriber lists.

Let’s take a closer look at GetResponse’s plans and pricing.

Email Marketing — Starting at $19 per month

  • Autoresponders
  • Unlimited newsletters
  • Basic segmentation
  • Website and landing pages
  • Integrations and API

Marketing Automation — Starting at $59 per month

  • Everything in Email Marketing, plus
  • Marketing and event-based automation
  • Advanced segmentation
  • Webinars with up to 100 attendees
  • Sales funnels

Ecommerce Marketing — Starting at $119 per month

  • Everything in Marketing Automation, plus
  • Quick transactional emails
  • Ecommerce segmentation
  • Abandoned cart recovery
  • Promo codes

These prices are all based on 1,000 subscribers. The rate will increase as your list grows. As you can see, even the entry-level plan offered by GetResponse comes with advanced features like autoresponders, signup forms and pop-ups.

All plans come with unlimited monthly email sends, inbox preview, click tracking, and 24/7 live chat support.

GetResponse offers discounts for annual and 24-month contracts if you pay in advance. At the very least, you can try GetResponse free for 30 days.

ConvertKit – Best for Influencers, Bloggers, and Creators

  • Price starts at $29 per month
  • Excellent for independent creators
  • Custom forms & reporting
  • Easy tagging and segmenting
Get a 14-day free trial

ConvertKit is one of my favorite email marketing services.

It’s a perfect choice for creators of all stripes. That includes influencers, bloggers, video producers, musicians, artists, and more. That’s because their platform focuses more on engaging your audience and nurturing them with landing pages, ecommerce platforms, and membership sites.

You’ll be able to create leads out of casual visitors to your social media accounts, blogs, YouTube videos, Facebook pages, and more.

For those of you who want to build automated email funnels at an affordable price, ConvertKit will be a top option for you to consider.

ConvertKit Features
ConvertKit excels at audience engagement and nurturing, making it a favorite with creators.

To set up automated emails, you’ll be guided through a simple visual flow chart.

Instead of having multiple lists of contacts, ConvertKit groups all of your subscribers into one list. But you’ll still be able to tag them manually for segmentation purposes or with auto tags based on their behavior to improve the personalization of your campaigns. That’s great for creators with big audiences.

ConvertKit is best for sending quick emails with clean formatting. There are no complex designs or distracting elements here.

ConvertKit offers three pricing plans:

  • Free — $0 per month up to 300 subscribers
  • Creator — $15 per month up to 300 subscriber
  • Creator Pro — $29 per month up to 300 subscribers

As you gain subscribers, the monthly price will increase accordingly. If you pay annually, you can get two months free.

ConvertKit has more than 70 third-party direct integrations, customizable forms, and custom reporting. Email and live chat are available for 12 hours per day, Monday through Friday, with limited support on nights and weekends.

Still not sold? Take advantage of ConvertKit’s free 14-day trial to test it out on your own.

Drip – Best for New Ecommerce Businesses

  • Price starts at $49 per month
  • 24/7 live chat and email support
  • CRM for ecommerce stores
  • Automatic revenue attribution
Get a 14-day free trial

Drip is a relatively new platform. It’s a CRM that offers email marketing for ecommerce businesses.

I like Drip because they’re great for new ecommerce merchants since they focus on offering smaller, independent shops the same powerful automation and segmentation tools for email marketing as larger ecommerce stores.

As such, they’re great for newer brands looking to get a leg up.

With Drip, you can track valuable commerce metrics related to customer intent and purchase behavior.

You’ll be able to segment new website visitors from returning customers. Drip also lets you target users who abandoned their carts.

Get nitty-gritty without hours of data mining–Drip gives you tools that make it easy to target the right people with timely offers.

Drip data mining tool.
Drip brings powerful automation and segmentation tools to small, independent shops, giving them the ability to compete with their bigger competition.

Their CRM helps you reach customers through multiple touchpoints online, including email. Drip also has a revenue attribution feature, giving you a clearer view of which campaigns are actually making you money.

Again, this is ideal for ecommerce shops.

With personalization capabilities, powerful segmentation options, and detailed analytics, Drip has everything you need to succeed with email marketing.

Pricing is based on the number of customers in your account. All plans come with the same features and benefits.

  • 1-2,500 subscribers — $39 per month
  • 2,501-3,000 subscribers — $49 per month
  • 3,001-3,500 subscribers — $59 per month
  • 3,501-4,000 subscribers — $69 per month
  • 4,101-4,500 subscribers — $79 per month
  • 4,501-5,000 subscribers — $89 per month

This stretches all the way up to plans that allow for up to 180,000 subscribers before pricing becomes custom.

All Drip plans come with 24/7 live chat and email support. You can try it out free for 14 days and have access to all of the features.

Moosend – Best for Ecommerce

  • Start for free
  • AI-powered ecommerce
  • Unlimited emails
  • Reporting & analytics
Try it for free

Moosend offers an email marketing solution no matter if you’re a complete beginner or if you’re a seasoned pro. If you have an online store, this is the perfect tool.

From their easy drag-and-drop email builder to their easy segmentation tool to their accurate real-time analytics, they have all the features you need to nail your email marketing campaigns.

Our favorite thing about Moosend is their ecommerce AI. It leverages machine learning and collaborative filtering to target customers with products they might like based on the shopping habits of similar customers.

Moosend AI ecommerce tool.
Moosend’s Ecommerce AI tool lets you target customers with products them might like based on the behavior of similar customers.

You’ll also be able to easily cross-sell based on customer shopping habits and keep track of how often they buy certain products (e.g., perishables), so you can regularly promote the products they need when they need them.

A lot of otherwise great email list services really struggle to give you this insight, if they can do it at all. Moosend makes it easy with a simple interface that lets any ecommerce business looking to level up its targeting and segmentation game.

Moosend targeting and segmentation tool and dashboard.
Moosend makes it easy to cross-sell based on detailed customer data displayed in a simple user interface.

Moosend also does the basics of email marketing very well. Their advanced personalization features allow you to create unique emails for your target customer. Their segmentation tool allows you to spit your audience by purchasing behavior, cart abandoned products, and more.

They don’t offer that many themes, with just 40 responsive themes to choose from. However, they’re all highly customizable and eye-catching.

Pricing starts free for a 30-day trial, with their premium plans starting at $9 per month. More detailed information is below:

Free — $0/first month

  • Unlimited emails
  • Signup and subscription forms
  • Reporting and analytics
  • No credit card required

Pro — $9/month

  • Landing pages
  • Transactional emails
  • Phone support
  • SMTP server
  • 5 team members

Enterprise — Custom pricing

  • Custom reporting
  • Dedicated account manager
  • SSO & SAML
  • On-boarding and migration
  • 10 team members
  • Service-level agreement

Try Moosend for free for 30 days.

How to Find the Best Email Marketing Service for You

The best available email marketing service is going to be unique to you. After all, the multi-million dollar info product business is going to have very different needs than the humble blogger.

But there are specific factors that we took into consideration because we believe that they tend to be the most important ones for most businesses.

I’ll break down the details of our process for making this list and explain what matters, what doesn’t, and what you need to know to find the best option for you.

Use our methodology to help guide your ultimate decision.

And while we don’t recommend using price as a deciding factor, if you’re just starting out and need to watch every penny, there are some solid free email marketing tools to consider, too.

Plenty of Email Templates

There are a lot of reasons to want an email marketing service. You might want to create your first sales funnel and incorporate email into your marketing strategy. Or maybe you just want to send the occasional newsletter out to subscribers.

Whatever your reason, you want your emails to look good while you do it.

That’s why you should find an email marketing service that takes the stress out of things like formatting and typesetting by giving you a list of great email templates for any of your needs.

Many of the offerings above offer drag-and-drop email templates to help take the headache out of designing a great-looking email. With tools like MailChimp’s email builder, you’re filling out the basic info, and a stunning email takes shape on its own.

Example of Hubspot email builder
look for a solution with a variety of templates that are easy to customize.

They’ll also offer a variety of different email template types to fit specific purposes.

For example, HubSpot comes with a library of pre-built sales email templates ready for you and your business to use. If you want, they’ll even allow you to create your own templates unique to your business. You can customize them to your exact needs and save them for use whenever you need them.

MailChimp is another great service with tons of different email templates for different needs, such as selling a product or promoting a blog post. It’s also highly customizable, allowing you to create specific ones for your brand’s goals.

Simple Segmentation

As your business grows, you’re going to want to target different parts of your audience for different products. After all, if you offer a variety of different services and products, not everyone on your list will want the same thing.

A good email marketing service gives you easy but powerful ways to segment your audience.

For example, a service like MailChimp allows you to tag segments of your audience depending on how they subscribed to your email list. That way, you can put those segments into specifically targeted funnels easily and automatically.

Omnisend subscriber segmentation screen
make sure you can segment your subscribers and that it is easy to do, like you can in Omnisend.

A service like Omnisend (pictured above) allows you to send segmented campaigns based on things like your subscriber’s interests, demographics, email open rates, and the products they’ve purchased.

It’s important to note: If you want segmentation features (and if you’re serious about email marketing, you should), you’re going to have to pay for it. This often doesn’t come with a service’s free plan. However, it’s well worth it, especially if you’re focused on growth and conversions.

Seriously–all the marketing automations, striking templates, and great writing in your campaigns depend on your ability to understand your audience. The perfect message is still an airball if it’s sent at the wrong time or to the wrong person.

Segmentation and other aspects of an email list service aren’t as flashy as some of the other features, but they are absolutely critical.

In-Depth Analytics

As the old business adage goes: “If you can measure it, you can improve it.”

To that end, a good email marketing service will give you all the reporting tools you need to provide you with in-depth metrics and KPIs.

Knowing this information will give you vital data about where your subscribers live, who they are, and what they want from your business.

It’ll also help you create better services and marketing strategies in the future. For example, you’ll be able to better segment your audiences with the right analytics.

HubSpot has some of the best traffic and conversion analytic tools available. Along with their A/B testing feature, their analytics tools will let you know exactly how each of your emails performs and why.

Hubspot analytics for A/B testing screen
Data is key to understanding email campaign performance, so be sure the solution you select makes it easy to find and understand the analytics.

Easy Automation

There’s nothing quite like the “set it and forget it” approach to business.

When an email marketing service is automated, you don’t have to worry about making sure that each and every one of your new subscribers is in the right sales funnel. Once you’ve set it up, they’ll receive the emails they should receive automatically.

That’s why you want to find an email marketing service that will let you easily set up automated emails without a lot of fuss and complex tagging schemes.

Constant Contact automation setup screen
Automation makes your life easier, so choose a solution that makes it easy to do.

Constant Contact (pictured above) is a standout when it comes to automating emails. It lets you trigger welcome messages for any new subscribers and put them into specific drip campaigns depending on their actions. The simple design allows you to do this easily, too, with no headaches involved.

GetResponse is another option to definitely consider if automation is your game. Its Autofunnel platform allows you to easily create fully automated sales, leads, and webinar funnels in just a few clicks.

Best Email Marketing Services: Your Top Questions Answered

Top Email Marketing Providers for 2023 in Summary

What’s the best email marketing service? I wish I could point you to just one, but your strategy, goals, audience, and budget are going to determine the right solution.

Use the reviews and methodology in this article to hone in on the perfect one for you. Here’s a recap of our top eight picks:

  • Constant Contact — Best overall
  • MailerLite — Best for the essentials at an affordable price
  • Salesforce – Best for scaling as your business grows
  • HubSpot – Best for automated email marketing
  • OmnisendBest email and SMS marketing combo
  • Brevo — Best for growing your customer base
  • SMTP.com – Best for high-volume email marketing
  • Campaigner – Best for marketing teams

Whether you’re starting a new list from scratch, switching providers, or looking for a full-service CRM, there’s an option for you above.

Kubernetes and Microservices Security

To understand the current and future state of Kubernetes (K8s) in the enterprise, we gathered insights from IT executives at 22 companies. We asked, "How does K8s help you secure containers?" Here’s what we learned.

Microservices, Security, and Kubernetes (K8s)

RBAC

  • K8s helps with authorization and authentication via workload identity. Role-based access control (RBAC) is provided out of the box. Service mesh ensures communication between microservices. 
  • K8s solves more problems than it creates. RBAC enforces relationships between resources like pod security policies to control the level of access pods have to each other, how many resources pods have access to. It’s too complicated but K8s provides tools to build a more stable infrastructure.
  • RBAC mechanisms. Good security profile and posture. K8s provides access and mechanisms to use other things to secure containers.
  • K8s provides a pluggable infrastructure so you can customize it to the security demands of your organization. The API was purpose-built for extensibility to ensure, for example, that you can scan workloads before they go into production clusters. You can apply RBAC rules for who can access your environments, and you can use webhooks for all kinds of sophisticated desired-state security and compliance policies that mitigate operational, security, and compliance risk.
  • The advantage of K8s is in its open-source ecosystem, which offers several security tools like CIS Benchmarks, Network Policy, Istio, Grafeas, Clair, etc. that can help you enforce security. K8s also has comprehensive support for RBAC on System and Custom resources. Container firewalls help enforce network security to K8s. Due to the increased autonomy of microservices deployed as pods in K8s, having a thorough vulnerability assessment on each service, change control enforcement on the security architecture, and strict security enforcement is critical to fending off security threats. Things like automated monitoring-auditing-alerting, OS hardening, and continuous system patching must be done. 
  • The great part about the industry adopting K8s as the de facto standard for orchestration means that many talented people have collaboratively focused on building secure best practices into the core system, such as RBAC, namespaces, and admission controllers. We take the security of our own architecture and that of our customers very seriously, and the project and other open-source supporting projects releasing patches and new versions quickly in the event of common vulnerabilities and exposures (CVE) makes it possible for us to always ensure we are keeping systems fully up to date. We have built-in support for automated K8s upgrades. We are always rolling out new versions and patches and providing our users with the notifications and tooling to keep their systems up to date and secure.

Reduced Exposure

  • You have services deployed individually in separated containers. Even if someone gets into a container, they’re only getting into one microservice, rather than being able to get into an entire server infrastructure. Integration with Istio provides virtualization and security on the access side.
  • Since the beginning, containers have been perceived as a potential security threat because you are running these entities on the same machine with low isolation. There's a perceived risk of data leakage, moving from one container to another. I see the security benefits of containers and K8s outweigh the risks because containers tend to be much smaller than a VM running NGINX will run a full OS with many processes and servers. Containers have far less exposure and attack surface. You can keep containers clean and small for minimal attack surface. K8s has a lot of security functionality embedded in the platform. Security is turned on by default with K8s. When you turn it on, there are a lot of security features in the platform. The microservices and container model is based on immutable infrastructure. You offer limited access to the container running the application. You're able to lock down containers in a better way and be in charge of what our application does. We are now using ML to understand what service or set of containers are doing and we can lock down the service. 
  • You need to look at security differently with containers to be more secure. Containers allow you to reduce the attack surface with fewer privileges. Limit access to the production environment. K8s has a number of security mechanisms built-in like authentication and authorization to control access to resources. You need to learn to configure. Be careful about setting the right privileges.

K8s Security Policies

  • My team helps with full and automatic application discovery spread across multiple data centers and cloud, and creating clean infrastructure policies and runtime discovery. Dynamic policies help lock down containers and apps built on top of containers.
  • You’re only as secure as you design yourself to be in the first place. By automating concepts and constructs of where things go using rules and stabilizing the environment, it eliminates a lot of human errors that occur in a manual configuration process. K8s standardizes the way we deploy containers. 
  • Namespaces, pod security policies, and network layer firewalling where we just define a policy using Calico and then kernel-level security that’s easy for us since we’re running on top of K8s. Kaneko runs Docker builds inside of Docker. Kaneko came out of Google. 
  • 1) Helps us with features like namespaces to segregate networks, from a team perspective. 2) Second is network policies. This pod cannot talk to that database and helps prevent mal-use of software.  3) Theres benefits from K8s protecting individual containers. This mitigates problems escaping from containers and helps you stay isolated.

Other

  • It’s not built-in per se, that’s why there are a number of security tools coming up. Things like scanning  Docker images. as K8s does not scan. A number of security companies are coming out with continuous scanning of Docker images before they are deployed, looking for security vulnerabilities during the SDLC. DevSecOps moves security checking and scanning to occur earlier in the development process. There are tools that are popping up to do that.
  • If you enable the security capabilities provided, it’s an advantage. There are capabilities in K8s that control whether you have the ability to pull up a container. It has to be set up correctly. You need to learn to use the capabilities. You need to think about the security of every container.
  • Security is a very important topic. One area is open source and the level of involvement and the number of developers involved can help drive greater security in the environment. Cloud-native security with the code and the cluster. For customers to leverage K8s in the cloud it changes the investment you have to make because you are inheriting the security capabilities of the cloud provider and dramatically lowering costs. K8s has API-level automation built-in.
  • Our container images are created using the Linux package security update mechanism to ensure the images include the latest security patches. Further, our container image is published to the Red Hat Container Catalog which requires these security measures to be applied as part of the publishing process. In addition, domain and database administrative commands are authenticated using TLS secure certificate authentication and LDAP, as well, domain meta-data, application SQL commands, and user data communications are all protected using the AES-256-CTR encryption cipher.
  • K8s provides only minimal structures for security, and it is largely the responsibility of implementers to provide security. You can build quite a lot on top of the Secrets API, such as implementing TLS in your applications or using it to store password objects.
  • K8s-orchestrated containerized environments and microservices present a large attack surface. The highly-dynamic container-to-container communications internal to these environments offer an opportune space for attacks to grow and escalate if they aren’t detected and thwarted. At the same time, K8s itself is drawing attackers’ attention: just last year a critical vulnerability exposing the K8s API server presented the first major known weakness in K8s security, but certainly not the last. To secure K8s environments, enterprises must introduce effective container network security and host security, which must include the visibility to closely monitor container traffic. Enterprise environments must be protected along each of the many vectors through which attackers may attempt entry. To do so, developers should implement security strategies featuring layer-7 inspection (capable of identifying any possible application layer issues). At the same time, the rise of production container environments that handle personally identifiable information (PII) has made data loss prevention a key security concern. This is especially true considering industry and governmental regulatory compliance requirements dictating how sensitive data must be handled and protected.

Here’s who shared their insights:

Model-Based Testing in React with State Machines

Testing applications is crucially important to ensuring that the code is error-free and the logic requirements are met. However, writing tests manually is tedious and prone to human bias and error. Furthermore, maintenance can be a nightmare, especially when features are added or business logic is changed. We’ll learn how model-based testing can eliminate the need to manually write integration and end-to-end tests, by automatically generating full tests that keep up-to-date with an abstract model for any app.

From unit tests to integration tests, end-to-end tests, and more, there are many different testing methods that are important in the development of non-trivial software applications. They all share a common goal, but at different levels: ensure that when anyone uses the application, it behaves exactly as expected without any unintended states, bugs, or worse, crashes.

Testing Trophy
Testing Trophy showing importance of different types of tests

Kent C. Dodds describes the practical importance of writing these tests in his article, Write tests. Not too many. Mostly integration. Some tests, like static and unit tests, are easy to author, but don't completely ensure that every unit will work together. Other tests, like integration and end-to-end (E2E) tests, take more time to author, but give you much more confidence that the application will work as the user expects, since they replicate scenarios similar to how a user would use the application in real life.

So why are there never many integration nor E2E in applications nowadays, yet hundreds (if not thousands) of unit tests? The reasons range from not enough resources, not enough time, or not enough understanding of the importance of writing these tests. Furthermore, even if numerous integration/E2E tests are written, if one part of the application changes, most of those long and complicated tests need to be rewritten, and new tests need to be written. Under deadlines, this quickly becomes infeasible.

From Automated to Autogenerated

The status-quo of application testing is:

  1. Manual testing, where no automated tests exist, and app features and user flows are tested manually
  2. Writing automated tests, which are scripted tests that can be executed automatically by a program, instead of being manually tested by a human
  3. Test automation, which is the strategy for executing these automated tests in the development cycle.

Needless to say, test automation saves a lot of time in executing the tests, but the tests still need to be manually written. It would sure be nice to tell some sort of tool: "Here is a description of how the application is supposed to behave. Now generate all the tests, even the edge cases."

Thankfully, this idea already exists (and has been researched for decades), and it's called model-based testing. Here's how it works:

  1. An abstract "model" that describes the behavior of your application (in the form of a directed graph) is created
  2. Test paths are generated from the directed graph
  3. Each "step" in the test path is mapped to a test that can be executed on the application.

Each integration and E2E test is essentially a series of steps that alternate between:

  1. Verify that the application looks correct (a state)
  2. Simulate some action (to produce an event)
  3. Verify that the application looks right after the action (another state)

If you’re familiar with the given-when-then style of behavioral testing, this will look familiar:

  1. Given some initial state (precondition)
  2. When some action occurs (behavior)
  3. Then some new state is expected (postcondition).

A model can describe all the possible states and events, and automatically generate the "paths" needed to get from one state to another, just like Google Maps can generate the possible routes between one location and another. Just like a map route, each path is a collection of steps needed to get from point A to point B.

Integration Testing Without a Model

To better explain this, consider a simple "feedback" application. We can describe it like so:

  • A panel appears asking the user, "How was your experience?"
  • The user can click "Good" or "Bad"
  • When the user clicks "Good," a screen saying "Thanks for your feedback" appears.
  • When the user clicks "Bad," a form appears, asking for further information.
  • The user can optionally fill out the form and submit the feedback.
  • When the form is submitted, the thanks screen appears.
  • The user can click "Close" or press the Escape key to close the feedback app on any screen.

See the Pen
Untitled by David Khourshid(
@davidkpiano)
on CodePen.

Manually Testing the App

The @testing-library/react library makes it straightforward to render React apps in a testing environment with its render() function. This returns useful methods, such as:

  • getByText, which identifies DOM elements by the text contained inside of them
  • baseElement, which represents the root document.documentElement and will be used to trigger a keyDown event
  • queryByText, which will not throw an error if a DOM element containing the specified text is missing (so we can assert that nothing is rendered)
import Feedback from './App';
import { render, fireEvent, cleanup } from 'react-testing-library';

// ...

// Render the feedback app
const {
  getByText,
  getByTitle,
  getByPlaceholderText,
  baseElement,
  queryByText
} = render(<Feedback />);

// ...

More information can be found in the @testing-library/react documentation. Let's write a couple integration tests for this with Jest (or Mocha) and @testing-library/react:

import { render, fireEvent, cleanup } from '@testing-library/react';

describe('feedback app', () => {
  afterEach(cleanup);

  it('should show the thanks screen when "Good" is clicked', () => {
    const { getByText } = render(<Feedback />);

    // The question screen should be visible at first
    assert.ok(getByText('How was your experience?'));

    // Click the "Good" button
    fireEvent.click(getByText('Good'));

    // Now the thanks screen should be visible
    assert.ok(getByText('Thanks for your feedback.'));
  });

  it('should show the form screen when "Bad" is clicked', () => {
    const { getByText } = render(<Feedback />);

    // The question screen should be visible at first
    assert.ok(getByText('How was your experience?'));

    // Click the "Bad" button
    fireEvent.click(getByText('Bad'));

    // Now the form screen should be visible
    assert.ok(getByText('Care to tell us why?'));
  });
});

Not too bad, but you'll notice that there's some repetition going on. At first, this isn't a big deal (tests shouldn't necessarily be DRY), but these tests can become less maintainable when:

  • Application behavior changes, such as adding a new steps or deleting steps
  • User interface elements change, in a way that might not even be a simple component change (such as trading a button for a keyboard shortcut or gesture)
  • Edge cases start occurring and need to be accounted for.

Furthermore, E2E tests will test the exact same behavior (albeit in a more realistic testing environment, such as a live browser with Puppeteer or Selenium), yet they cannot reuse the same tests since the code for executing the tests is incompatible with those environments.

The State Machine as an Abstract Model

Remember the informal description of our feedback app above? We can translate that into a model that represents the different states, events, and transitions between states the app can be in; in other words, a finite state machine. A finite state machine is a representation of:

  • The finite states in the app (e.g., question, form, thanks, closed)
  • An initial state (e.g., question)
  • The events that can occur in the app (e.g., CLICK_GOOD, CLICK_BAD for clicking the good/bad buttons, CLOSE for clicking the close button, and SUBMIT for submitting the form)
  • Transitions, or how one state transitions to another state due to an event (e.g., when in the question state and the CLICK_GOOD action is performed, the user is now in the thanks state)
  • Final states (e.g., closed), if applicable.

The feedback app's behavior can be represented with these states, events, and transitions in a finite state machine, and looks like this:

State diagram of example Feedback app

A visual representation can be generated from a JSON-like description of the state machine, using XState:

import { Machine } from 'xstate';

const feedbackMachine = Machine({
  id: 'feedback',
  initial: 'question',
  states: {
    question: {
      on: {
        CLICK_GOOD: 'thanks',
        CLICK_BAD: 'form',
        CLOSE: 'closed'
      }
    },
    form: {
      on: {
        SUBMIT: 'thanks',
        CLOSE: 'closed'
      }
    },
    thanks: {
      on: {
        CLOSE: 'closed'
      }
    },
    closed: {
      type: 'final'
    }
  }
});

https://xstate.js.org/viz/?gist=e711330f8aad8b52da76419282555820

If you're interested in diving deeper into XState, you can read the XState docs, or read a great article about using XState with React by Jon Bellah. Note that this finite state machine is used only for testing, and not in our actual application — this is an important principle of model-based testing, because it represents how the user expects the app to behave, and not its actual implementation details. The app doesn’t necessarily need to be created with finite state machines in mind (although it’s a very helpful practice).

Creating a Test Model

The app's behavior is now described as a directed graph, where the nodes are states and the edges (or arrows) are events that denote the transitions between states. We can use that state machine (the abstract representation of the behavior) to create a test model. The @xstate/graph library contains a createModel function to do that:

import { Machine } from 'xstate';
import { createModel } from '@xstate/test';

const feedbackMachine = Machine({/* ... */});

const feedbackModel = createModel(feedbackMachine);

This test model is an abstract model which represents the desired behavior of the system under test (SUT) — in this example, our app. With this testing model, test plans can be created which we can use to test that the SUT can reach each state in the model. A test plan describes the test paths that can be taken to reach a target state.

Verifying States

Right now, this model is a bit useless. It can generate test paths (as we’ll see in the next section) but to serve its purpose as a model for testing, we need to add a test for each of the states. The @xstate/test package will read these test functions from meta.test:

const feedbackMachine = Machine({
  id: 'feedback',
  initial: 'question',
  states: {
    question: {
      on: {
        CLICK_GOOD: 'thanks',
        CLICK_BAD: 'form',
        CLOSE: 'closed'
      },
      meta: {
        // getByTestId, etc. will be passed into path.test(...) later.
        test: ({ getByTestId }) => {
          assert.ok(getByTestId('question-screen'));
        }
      }
    },
    // ... etc.
  }
});

Notice that these are the same assertions from the manually written tests we’ve created previously with @testing-library/react. The purpose of these tests is to verify the precondition that the SUT is in the given state before executing an event.

Executing Events

To make our test model complete, we need to make each of the events, such as CLICK_GOOD or CLOSE, “real” and executable. That is, we have to map these events to actual actions that will be executed in the SUT. The execution functions for each of these events are specified in createModel(…).withEvents(…):

import { Machine } from 'xstate';
import { createModel } from '@xstate/test';

const feedbackMachine = Machine({/* ... */});

const feedbackModel = createModel(feedbackMachine)
  .withEvents({
    // getByTestId, etc. will be passed into path.test(...) later.
    CLICK_GOOD: ({ getByText }) => {
      fireEvent.click(getByText('Good'));
    },
    CLICK_BAD: ({ getByText }) => {
      fireEvent.click(getByText('Bad'));
    },
    CLOSE: ({ getByTestId }) => {
      fireEvent.click(getByTestId('close-button'));
    },
    SUBMIT: {
      exec: async ({ getByTestId }, event) => {
        fireEvent.change(getByTestId('response-input'), {
          target: { value: event.value }
        });
        fireEvent.click(getByTestId('submit-button'));
      },
      cases: [{ value: 'something' }, { value: '' }]
    }
  });

Notice that you can either specify each event as an execution function, or (in the case of SUBMIT) as an object with the execution function specified in exec and sample event cases specified in cases.

From Model To Test Paths

Take a look at the visualization again and follow the arrows, starting from the initial question state. You'll notice that there are many possible paths you can take to reach any other state. For example:

  • From the question state, the CLICK_GOOD event transitions to...
  • the form state, and then the SUBMIT event transitions to...
  • the thanks state, and then the CLOSE event transitions to...
  • the closed state.

Since the app's behavior is a directed graph, we can generate all the possible simple paths or shortest paths from the initial state. A simple path is a path where no node is repeated. That is, we're assuming the user isn't going to visit a state more than once (although that might be a valid thing to test for in the future). A shortest path is the shortest of these simple paths.

Rather than explaining algorithms for traversing graphs to find shortest paths (Vaidehi Joshi has great articles on graph traversal if you're interested in that), the test model we created with @xstate/test has a .getSimplePathPlans(…) method that generates test plans.

Each test plan represents a target state and simple paths from the initial state to that target state. Each test path represents a series of steps to get to that target state, with each step including a state (precondition) and an event (action) that is executed after verifying that the app is in the state.

For example, a single test plan can represent reaching the thanks state, and that test plan can have one or more paths for reaching that state, such as question -- CLICK_BAD → form -- SUBMIT → thanks, or question -- CLICK_GOOD → thanks:

testPlans.forEach(plan => {
  describe(plan.description, () => {
    // ...
  });
});

We can then loop over these plans to describe each state. The plan.description is provided by @xstate/test, such as reaches state: "question":

// Get test plans to all states via simple paths
const testPlans = testModel.getSimplePathPlans();

And each path in plan.paths can be tested, also with a provided path.description like via CLICK_GOOD → CLOSE:

testPlans.forEach(plan => {
  describe(plan.description, () => {
    // Do any cleanup work after testing each path
    afterEach(cleanup);

    plan.paths.forEach(path => {
      it(path.description, async () => {
        // Test setup
        const rendered = render(<Feedback />);

        // Test execution
        await path.test(rendered);
      });
    });
  });
});

Testing a path with path.test(…) involves:

  1. Verifying that the app is in some state of a path’s step
  2. Executing the action associated with the event of a path’s step
  3. Repeating 1. and 2. until there are no more steps
  4. Finally, verifying that the app is in the target plan.state.

Finally, we want to ensure that each of the states in our test model were tested. When the tests are run, the test model keeps track of the tested states, and provides a testModel.testCoverage() function which will fail if not all states were covered:

it('coverage', () => {
  testModel.testCoverage();
});

Overall, our test suite looks like this:

import React from 'react';
import Feedback from './App';
import { Machine } from 'xstate';
import { render, fireEvent, cleanup } from '@testing-library/react';
import { assert } from 'chai';
import { createModel } from '@xstate/test';

describe('feedback app', () => {
  const feedbackMachine = Machine({/* ... */});
  const testModel = createModel(feedbackMachine)
    .withEvents({/* ... */});

  const testPlans = testModel.getSimplePathPlans();
  testPlans.forEach(plan => {
    describe(plan.description, () => {
      afterEach(cleanup);
      plan.paths.forEach(path => {
        it(path.description, () => {
          const rendered = render(<Feedback />);
          return path.test(rendered);
        });
      });
    });
  });

  it('coverage', () => {
    testModel.testCoverage();
  });
});

This might seem like a bit of setup, but manually scripted integration tests need to have all of this setup anyway, in a much less abstracted way. One of the major advantages of model-based testing is that you only need to set this up once, whether you have 10 tests or 1,000 tests generated.

Running the Tests

In create-react-app, the tests are ran using Jest via the command npm test (or yarn test). When the tests are ran, assuming they all pass, the output will look something like this:

PASS  src/App.test.js
feedback app
  ✓ coverage
  reaches state: "question" 
    ✓ via  (44ms)
  reaches state: "thanks" 
    ✓ via CLICK_GOOD (17ms)
    ✓ via CLICK_BAD → SUBMIT ({"value":"something"}) (13ms)
  reaches state: "closed" 
    ✓ via CLICK_GOOD → CLOSE (6ms)
    ✓ via CLICK_BAD → SUBMIT ({"value":"something"}) → CLOSE (11ms)
    ✓ via CLICK_BAD → CLOSE (10ms)
    ✓ via CLOSE (4ms)
  reaches state: "form" 
    ✓ via CLICK_BAD (5ms)

Test Suites: 1 passed, 1 total
Tests:       9 passed, 9 total
Snapshots:   0 total
Time:        2.834s

That's nine tests automatically generated with our finite state machine model of the app! Every single one of those tests asserts that the app is in the correct state and that the proper actions are executed (and validated) to transition to the next state at each step, and finally asserts that the app is in the correct target state.

These tests can quickly grow as your app gets more complex; for instance, if you add a back button to each screen or add some validation logic to the form page (please don't; be thankful the user is even going through the feedback form in the first place) or add a loading state submitting the form, the number of possible paths will increase.

Advantages of Model-Based Testing

Model-based testing greatly simplifies the creation of integration and E2E tests by autogenerating them based on a model (like a finite state machine), as demonstrated above. Since manually writing full tests is eliminated from the test creation process, adding or removing new features no longer becomes a test maintenance burden. The abstract model only needs to be updated, without touching any other part of the testing code.

For example, if you want to add the feature that the form shows up whether the user clicks the "Good" or "Bad" button, it's a one-line change in the finite state machine:

// ...
    question: {
      on: {
//      CLICK_GOOD: 'thanks',
        CLICK_GOOD: 'form',
        CLICK_BAD: 'form',
        CLOSE: 'closed',
        ESC: 'closed'
      },
      meta: {/* ... */}
    },
// ...

All tests that are affected by the new behavior will be updated. Test maintenance is reduced to maintaining the model, which saves time and prevents errors that can be made in manually updating tests. This has been shown to improve efficiency in both developing and testing production applications, especially as used at Microsoft on recent customer projects — when new features were added or changes made, the autogenerated tests gave immediate feedback on which parts of the app logic were affected, without needing to manually regression test various flows.

Additionally, since the model is abstract and not tied to implementation details, the exact same model, as well as most of the testing code, can be used to author E2E tests. The only things that would change are the tests for verifying the state and the execution of the actions. For example, if you were using Puppeteer, you can update the state machine:

// ...
question: {
  on: {
    CLICK_GOOD: 'thanks',
    CLICK_BAD: 'form',
    CLOSE: 'closed'
  },
  meta: {
    test: async (page) => {
      await page.waitFor('[data-testid="question-screen"]');
    }
  }
},
// ...
const testModel = createModel(/* ... */)
  .withEvents({
    CLICK_GOOD: async (page) => {
      const goodButton = await page.$('[data-testid="good-button"]');
      await goodButton.click();
    },
    // ...
  });

And then these tests can be run against a live Chromium browser instance:

End-to-end tests for Feedback app being run in a browser

The tests are autogenerated the same, and this cannot be overstated. Although it just seems like a fancy way to create DRY test code, it goes exponentially further than that — autogenerated tests can exhaustively represent paths that explore all the possible actions a user can do at all possible states in the app, which can readily expose edge-cases that you might not have even imagined.

The code for both the integration tests with @testing-library/react and the E2E tests with Puppeteer can be found in the the XState test demo repository.

Challenges to Model-Based Testing

Since model-based testing shifts the work from manually writing tests to manually writing models, there is a learning curve. Creating the model necessitates the understanding of finite state machines, and possibly even statecharts. Learning these are greatly beneficial for more reasons than just testing, since finite state machines are one of the core principles of computer science, and statecharts make state machines more flexible and scalable for complex app and software development. The World of Statecharts by Erik Mogensen is a great resource for understanding and learning how statecharts work.

Another issue is that the algorithm for traversing the finite state machine can generate exponentially many test paths. This can be considered a good problem to have, since every one of those paths represents a valid way that a user can potentially interact with an app. However, this can also be computationally expensive and result in semi-redundant tests that your team would rather skip to save testing time. There are also ways to limit these test paths, e.g., using shortest paths instead of simple paths, or by refactoring the model. Excessive tests can be a sign of an overly complex model (or even an overly complex app 😉).

Write Fewer Tests!

Modeling app behavior is not the easiest thing to do, but there are many benefits of representing your app as a declarative and abstract model, such as a finite state machine or a statechart. Even though the concept of model-based testing is over two decades old, it is still an evolving field. But with the above techniques, you can get started today and take advantage of generating integration and E2E tests instead of manually writing every single one of them.

More resources:

I gave a talk at React Rally 2019 demonstrating model-based testing in React apps:

Slides: Slides: Write Fewer Tests! From Automation to Autogeneration

Happy testing!

The post Model-Based Testing in React with State Machines appeared first on CSS-Tricks.

Firefox blocks third-party tracking cookies and cryptominers

This is super interesting stuff from Mozilla: the most recent update of Firefox will now block cryptominers and third-party tracking scripts by default. In the press release they write:

For today’s release, Enhanced Tracking Protection will automatically be turned on by default for all users worldwide as part of the ‘Standard’ setting in the Firefox browser and will block known “third-party tracking cookies” according to the Disconnect list. We first enabled this default feature for new users in June 2019. As part of this journey we rigorously tested, refined, and ultimately landed on a new approach to anti-tracking that is core to delivering on our promise of privacy and security as central aspects of your Firefox experience.

Compare this to A Vox interview with Mat Marquis discussing Google's efforts to make Chrome more private:

“Google is an advertising company, not a group of concerned altruists; there aren’t any charts at stakeholder meetings showing what amount they ‘saved the web’ this past quarter. They’re notorious for overstepping and outright abusing users’ personal data in pursuit of, well, making money as an advertising company,” Mat Marquis, a web developer, told Recode. “Their business model — the thing that keeps all these genuinely brilliant, genuinely well-meaning designers and developers employed — depends on convincing a company that they can make their users look at your ads.”

This is yet another reason why Firefox is my browser of choice and why, as concerned web designers and developers, I suggest others consider joining me in making the switch.

Direct Link to ArticlePermalink

The post Firefox blocks third-party tracking cookies and cryptominers appeared first on CSS-Tricks.

How to Add a Search Bar to WordPress Menu (Step by Step)

Do you want to add a search bar to your WordPress navigation menu?

By default, WordPress lets you add a search section on your website sidebar, footer, and other widget-ready areas. However, many users prefer to have the WordPress search box in the navigation menu because it is easily noticeable on the top.

In this article, we will show you how to easily add a search bar to your WordPress menu without having any coding knowledge.

Adding a Search Bar to WordPress Menu

Why You Should Add a Search Bar in Menu?

A site search makes it easy for your users to find what they’re looking for without leaving your website. It helps improve user experience on your website and boosts engagement.

This is why most usability experts recommend adding a search option in the navigation menu, so users can easily find it.

However, the default WordPress search widget is limited to only widget-ready areas.

Luckily, there are many different WordPress search plugins which let you add the search bar to different locations on your site including menus.

For this tutorial, we have chosen the Ivory Search free plugin. It allows you to create new custom search forms and enhance the default WordPress search.

With that said, let’s take a look at how to add a search bar to your WordPress menu.

Adding a Search Bar to WordPress Menu

First thing you need to do is to install and activate the Ivory Search plugin. For more details, see our step by step guide on how to install a WordPress plugin.

Upon activation, you need to visit Ivory Search » Search Forms page to create a new search form.

Ivory Search Include Options

The plugin automatically adds the default search form, so you can quickly review its settings and add it to your WordPress menu.

Search settings allow you to select which content on your website should be included in the site search.

The ‘Includes’ section lets you choose which post types, posts, pages, category, custom fields, etc. should be included in the search query. You need to review the options and click the Save Form button.

Next, there is the ‘Excludes’ section, which lets you define the content that you don’t want to show in search results. Once done, click the Save Form button again to store your settings.

Ivory Search Exclude Options

The ‘AJAX’ section lets you enable AJAX functionality for your search form.

Ivory WordPress Search Bar AJAX Settings

The ‘Options’ section lets you define how many results to show per search page along with other advanced settings.

Define Search Results Per Page in Ivory Search Plugin

Now your custom WordPress search form is ready. Once again, don’t forget to save your settings.

After that, the next step is to add the search form to your navigation menu. Simply go to Ivory Search » Settings page to configure the search bar to your WordPress menu.

On this page, you will see the ‘Select Menu’ tab. From here, you can simply toggle the menu where you would like to add the search bar.

Select WordPress Menu to Show Search Bar

This list of menus (Primary Menu and Footer Menu) belongs to your WordPress template. If you change the template of your site, then the list will be automatically updated with the available menus from your template.

After that, you can choose the search style from the Form Style accordion below.

The plugin allows you to display the search form in five different styles: Default, dropdown, sliding, full width, and popup.

Ivory Search Form Styles

If you like, you can further customize the options by going to the ‘Settings’ section below ‘Menu Search’.

From there, you can add your search form to the header, footer, manage mobile display for search, and more. These settings will also help in controlling the search results for your users.

Ivory Search More Settings

Once you are satisfied, make sure to save your settings. After that, you can head over to your website to see the search bar in the WordPress navigation menu.

Search Bar in WordPress Menu Preview

We hope this article helped you learn how to add a search bar to a WordPress menu. You may also want to see our list of most useful tips to speed up WordPress and boost performance.

If you liked this article, then please subscribe to our YouTube Channel for WordPress video tutorials. You can also find us on Twitter and Facebook.

The post How to Add a Search Bar to WordPress Menu (Step by Step) appeared first on WPBeginner.

A Configurator for Creating Custom WebGL Distortion Effects

In one of our previous tutorials we showed you how to create thumbnail to fullscreen WebGL distortion animations. Today we would like to invite you to build your own personalized effects by using the configurator we’ve created.

We’ll briefly go over some main concepts so you can make full use of the configurator. If you’d like to understand the main idea behind the work, and why the animations behave the way they do in more depth, we highly recommend you to read the main tutorial Creating Grid-to-Fullscreen Animations with Three.js.

Basics of the configurator

The configurator allows you to modify all the details of the effect, making it possible to create unique animations. Even though you don’t have to be a programmer to create your own effect, understanding the options available will give you more insight into what you can achieve with it.

To see your personalized effect in action, either click on the image or drag the Progress bar. The Duration option sets the time of the whole animation.

Under Easings you can control the “rate of change” of your animation. For example:

  • Power1.easeOut: Start really fast but end slowly
  • Power1.easeInOut: Start and end slowly, but go really fast in the middle of the animation
  • Bounce: Bounce around like a basketball

The simplest easings to play around with are Power0-4 with ease-out. If you would like to know the difference between each easing, check out this ease visualizer.

Note that the configurator automatically saves your progress for later use. Feel free to close the page and come back to it later.

Timing, Activation and Transformation

Timing, Activation and Transformation are concepts that come from our previous tutorial. Each on of them has their own list of types, that also have their own set of options for you to explore.

You can explore them by changing the types, and expanding the respective options tab. When you swap one type for another, your previous set of options is saved in case you want to go back to it.

configurator

Timing

The timing function maps the activation into actual progress for each vertex. Without timing, the activation doesn’t get applied and all the vertices move at the same rate. Set timing type to none to see it in action.

  • SameEnd: The vertices have different start times, but they all end at the same time. Or vice versa.
  • sections: Move by sections, wait for the previous section to finish before starting.

The same activation with a different timing will result in a very different result.

Activation

The activation determines how the plane is going to move to full screen:

  • side: From left to right.
  • corners: From top-left to bottom-right
  • radial: From the position of the mouse
  • And others.

For a visual representation of the current activation, toggle debug activation and start the animation to see it in action.

Transformation

Transform the plane into a different shape or position over the course of the animation:

  • Flip: Flip the plane on the X axis
  • simplex: Move the vertices with noise over the while transitioning
  • wavy: Make the plane wavy while transitioning
  • And more

Some effects, use seed for their inner workings. You can set the initial seed and determine when this seed is going to be randomized.

Note that although these three concepts allow for a large amount of possible effects, some options won’t work quite well together.

Sharing your effect

To share the effect you can simply copy and share the URL.

We would love to see what you come up with. Please share your effect in the comments or tag us on Twitter using @anemolito and @codrops.

Adding your effect to your site

Now that you made your custom effect, it is time to add it to your site. Let’s see how to do that, step by step.

First, download the code and copy some of the required files over:

  • THREEjs: js/three.min.js
  • TweenLite: js/TweenLite.min.js
  • ImagesLoaded: js/imagesloaded.pkgd.min.js
  • For preloading the images
  • The effect’s code: js/GridToFullscreenEffect.js
  • TweenLite’s CSSPlugin: js/CSSPlugin.min.js (optional)
  • TweenLite’s EasePack:js/EasePack.min.js (optional; if you use the extra easings)

Include these in your HTML file and make sure to add js/GridToFullscreenEffect.js last.

Now let’s add the HTML structure for the effect to work. We need two elements:

  • div#App: Where our canvas is going to be
  • div#itemsWrapper: Where our HTML images are going to be
<body>
    <div id="app"></div>
    <div id="itemsWrapper"></div>    
</body>

Note: You can use any IDs or classes you want as long as you use them when instantiating the effect.

Inside #itemsWrapper we are going to have the HTML items for our effect.

Our HTML items inside #itemsWrapper can have almost any structure. The only requirement is that it has two image elements as the first two children of the item.

The first element is for the small-scale image and the second element is the large-scale image.

Aside from that, you can have any caption or description you may want to add at the bottom. Take a look at how we did ours in our previous post:

<div id="app"></div>
<div id="itemsWrapper">
    <figure class="grid__item">
        <img class="grid__item-img" src="img/1.jpg" alt="An image" />
        <img class="grid__item-img grid__item-img--large" src="img/1_large.jpg" />
        <figcaption class="grid__item-caption">
            <h2 class="grid__item-title">Our Item Title</h2>
            <p class="grid__item-text">
                Our Item Description
            </p>
        </figcaption>
    </figure>
    ...
</div>

You may add as many items as you want. If you add enough items to make your container scrollable. Make sure to send your container in the options, so the effect can account for its scroll.

With our HTML items in place, let’s get the effect up and running.

We’ll instantiate GridToFullscreenEffect, add our custom options, and initialize it.

<script>
  const transitionEffect = new GridToFullscreenEffect(
        document.getElementById("app"),
        document.getElementById("itemsWrapper"),
      {
          "duration":1.8,
          "timing":{"type":"sameEnd","props":{"latestStart":0.5,"reverse":true}},
          "activation":{"type":"snake","props":{"rows":4}},
          "transformation":{"type":"flipX"},
          "easings":{"toFullscreen":Quint.easeOut,"toGrid":Quint.easeOut}
      }
  );
  transitionEffect.init();
</script>

Our effect is now mounted and working. But clicking on an item makes the image disappear and we end up with a black square.

The effect doesn’t take care of loading the images. Instead, it requires you to give them to the effect whenever they load. This might seem a bit inconvenient, but it allows you to load your images the way it’s most suitable for your application.

You could preload all the images upfront, or you could only load the images that are on screen, and load the other ones when needed. It’s up to how you want to do that.

We decided to preload all the images using imagesLoaded like this:

imagesLoaded(document.querySelectorAll("img"), instance => {
    document.body.classList.remove("loading");

    // Make Images sets for creating the textures.
    let images = [];
    for (var i = 0, imageSet = {}; i < instance.elements.length; i++) {
        let image = {
            element: instance.elements[i],
            image: instance.images[i].isLoaded ? instance.images[i].img : null
        };
        if (i % 2 === 0) {
            imageSet = {};
            imageSet.small = image;
        }

        if (i % 2 === 1) {
            imageSet.large = image;
            images.push(imageSet);
        }
    }
    configurator.effect.createTextures(images);
});

With that last piece of code, our effect is running and it shows the correct images. If you are having troubles with adding it to your site, let us know!

Our Creations

While working on this configurator, we managed to create some interesting results of our own. Here are three examples. You can use the parameters and attach it to the URL or use the settings:

Preset 1

?duration=1.75&toFull=Cubic.easeInOut&toGrid=Cubic.easeInOut&timing=sections%2Csections%2C4&transformation=simplex&activation=side%2Ctop%2Ctrue%2Cbottom%2Ctrue
{"timing":{"type":"sections","props":{"sections":4}},"activation":{"type":"side","props":{"top":true,"bottom":true}},"transformation":{"type":"simplex"},"duration":1.75,"easings":{"toFullscreen":"Cubic.easeInOut","toGrid":"Cubic.easeInOut"}}

Preset 2

?duration=1.75&toFull=Cubic.easeInOut&toGrid=Cubic.easeInOut&timing=sections%2Csections%2C4&transformation=simplex&activation=side%2Ctop%2Ctrue%2Cbottom%2Ctrue
{"timing":{"type":"sections","props":{"sections":4}},"activation":{"type":"side","props":{"top":true,"bottom":true}},"transformation":{"type":"simplex"},"duration":1.75,"easings":{"toFullscreen":"Cubic.easeInOut","toGrid":"Cubic.easeInOut"}}

Preset 4

?duration=1.75&toFull=Cubic.easeInOut&toGrid=Cubic.easeInOut&timing=sections%2Csections%2C4&transformation=simplex&activation=side%2Ctop%2Ctrue%2Cbottom%2Ctrue
{"timing":{"type":"sections","props":{"sections":4}},"activation":{"type":"side","props":{"top":true,"bottom":true}},"transformation":{"type":"simplex"},"duration":1.75,"easings":{"toFullscreen":"Cubic.easeInOut","toGrid":"Cubic.easeInOut"}}

Check out all the demos to explore more presets!

We hope you enjoy the configurator and find it useful for creating some unique animations!

A Configurator for Creating Custom WebGL Distortion Effects was written by Daniel Velasquez and published on Codrops.

Overflow And Data Loss In CSS

Overflow And Data Loss In CSS

Overflow And Data Loss In CSS

Rachel Andrew

CSS is designed to keep your content readable. If you consider an HTML document that is marked up with headings and paragraphs (with no CSS applied), it displays in the browser in a readable way. The headings are large and bold, and the paragraphs have space between them which is controlled by the browser default stylesheet. As soon as you want to change the layout of your page, however, you start to take some of the control into your own hands. In some cases, this will mean that you give yourself the job of dealing with overflow.

In this article, I’m going to take a look at the different ways we encounter overflow on the web. We’ll see how new layout methods and new values in CSS can help us to deal with overflow and create less fragile designs. I’ll also explain one of the fundamental concepts behind the design of CSS — that of avoiding data loss.

CSS Lists, Markers, And Counters

There is more to styling lists in CSS than you might think. Let’s take a look at lists in CSS, and moving onto some interesting features defined in the CSS Lists specification: markers and counters. Read more  →

What Do We Mean By Overflow?

If we look back a few years (before the advent of layout methods such as Flexbox and Grid Layout), then consider being handed a design like the one below. A very simple layout of three boxes, different amounts of content in each, but the bottom of those boxes needs to line up:

Screenshot three boxes, variable amounts of content, the bottoms of the boxes line up
A neat set of boxes (Large preview)

With a floated layout, such a seemingly straightforward task was impossible. When floated, each box has no relationship to its neighbor; this means that has no way to know that the next door box is taller and to grow to match the height.

Screenshot three boxes, variable amounts of content, the bottoms of the boxes do not line up
The box bottoms do not align (Large preview)

Sometimes, in an attempt to make things line up, designers would then restrict the height of the boxes by second-guessing the amount of content in order to make the boxes tall enough to match. Of course, things are never that simple on the web and when the amount of content differed, or the text size was larger, the text would start to poke out of the bottom of the box. It would overflow.

Screenshot three boxes, variable amounts of content, content overflowing the bottom of the box
Overflow caused by fixing the box heights (Large preview)

This would sometimes lead to people asking how they could prevent too much content getting into the site. I’ve had people in support for my own CMS product asking how to restrict content for this very reason. They tell me that this extra content is “breaking the design”. For those of us who understood that not knowing how tall things were was a fundamental nature of web design, we would create designs that hid the lack of equal height boxes. A common pattern would have a gradient fading away — to mask the unevenness. We would avoid using background colors and borders on boxes. Or, we would use techniques such as faux columns to create the look of full-height columns.

This inability to control the height of things in relationship to other things therefore influenced web design — a technical limitation changing the way we designed. (I enjoy the fact that with Flexbox and Grid.) Not only did this problem disappear but the default behavior of these new layout methods is to stretch the boxes to the same height. The initial value of align-items is stretch, which causes the boxes to stretch to the height of the grid area or flex container.

See the Pen [Equal Height Boxes](https://codepen.io/rachelandrew/pen/VwZzxjV) by Rachel Andrew.

See the Pen Equal Height Boxes by Rachel Andrew.

In addition, CSS Grid gives us a nice way to ask for things to be at least a certain size, but grow larger if they need to. If you set a track size using the minmax() function, you can see a minimum and maximum size for the track. Setting rows to minmax(200px, auto) means that the track will always be at least 200 pixels in the block dimension — even if the grid items are empty. If, however, the content of a grid item means that it will be larger than 200 pixels, with the max set to auto it can grow. You can see this in the example below: The first row is 200 pixels as there are no items making it larger. The second row has a grid item with more content in than will fit, and so auto is being used and the track has grown larger than 200 pixels.

See the Pen [Minmax()](https://codepen.io/rachelandrew/pen/zYOdjKP) by Rachel Andrew.

See the Pen Minmax() by Rachel Andrew.

The minmax() function gives you the ability to create designs that look as if they have that perfect fixed size. In an ideal world (when the amount of content is pretty much as you expected), you will get those nice uniform rows. However, if additional content is added, there will be no overflow as there would be if you had fixed the height of the rows to 200 pixels. The row will expand; it might not be exactly what you wanted as a designer, but it will not be unreadable.

Inline Overflow

The potential for overflow happens whenever we restrict the size of things. In the above example, I am describing restriction in the block dimension, which horizontal language users will think of as height. However, we can also end up with overflow in the inline direction if we restrict the inline size or width of a box. This is something that we see in the “CSS is Awesome” meme:

Image contains the words ‘CSS is Awesome’ in a bordered box. The word awesome is too long to fit in the box so pokes out past the border
The ‘CSS Is Awesome’ meme (Large preview)

The author of this meme commented on a CSS-Tricks post about it saying,

“I do have a slightly better grasp on the concept of overflow now, but at the time it just blew my mind that someone thought the default behavior should be to just have the text honk right out of the box, instead of just making the box bigger like my nice, sensible tables had always done.”

So why does CSS make the text “honk right out of the box” rather than grow the box?

In the meme, you have overflow in the inline direction. The word “awesome” is larger than the width applied to the box, and so it overflows. CSS fairly reasonably assumes that if you have made the box a certain width, you want the box that width. Perhaps it needs to fit into a layout which would break if boxes suddenly became larger than set.

That particular issue (i.e. the need to set sizes on everything in a layout and making sure they did not total more than the available inline size of the container) is something that our modern layout methods have addressed for us. If we imagine that our box had that absolute inline size so that it could fit in a line with other boxes in a float-based grid, today you might choose to approach that layout using Flexbox.

With the floated layout, you have to set the sizing on each item — potentially before you know what the content will be. You will then have big things forced into small containers and small things left with a lot of space around them.

Irregular sized items in regular sized boxes
Items in a floated layout need to have a width set (Large preview)

However, if we use Flexbox, we can allow the browser to work out how much space to assign each item. Flexbox will then ensure that bigger things get assigned more space while smaller things get less. This squishy sizing means that the box that contains the word “awesome” will grow to contain the box, and the text won’t honk right out or overlap anything else. Overflow issue solved; this behavior is really what Flexbox was designed for. Flexbox excels at taking a bunch of unevenly sized stuff and returning the most useful layout for those things.

Irregular sized items in boxes which are sized to make best use of space
Flexbox distributes space between the items (Large preview)

Outside of Flexbox, it is possible to tell our box to be as big as is needed for the content and no more. The min-content keyword can be used as a value for width or inline-size if working with flow-relative logical properties. Set width: min-content and the box grows just as big as is needed to contain the word “awesome”:

See the Pen [Awesome with min-content](https://codepen.io/rachelandrew/pen/LYPjmbJ) by Rachel Andrew.

See the Pen Awesome with min-content by Rachel Andrew.

Avoiding Data Loss

The reason that the box overflows as it does (with the word escaping from the border of the box), is that the default value for the overflow property is visible. You could (if you wanted) manage that overflow in a different way. For example, using overflow: auto or overflow: scroll would give your box scrollbars. This is probably not something you want in this scenario, but there are design patterns where a scrolling box is appropriate.

Another possibility would be to decide that you are happy to crop the overflow by using overflow: hidden. Perhaps you might think that hiding the overflow would have been a better default, however, the fact that CSS chooses to make the overflow visible by default (and not hidden) is a clue to a core value of designing CSS. In CSS (as in most places), we try to avoid data loss. When we talk about data loss in CSS, we are typically describing some of your content going missing. In the case of overflow: hidden, the overflowing content disappears. This means that we have no way to get to it to see what we have missed out on.

In some cases, this could be a real problem. If you have managed to create a design so fragile that the button of your form is in the cropped-off area, your user has no ability to complete the form. If the final paragraph is trimmed off, we never know how the story ends! Also, the problem with things vanishing is that it isn’t always obvious that they have gone. As the designer, you may not spot the problem, especially if it only happens in certain viewport sizes in a responsive design. Your users may not spot the problem — they just don’t see the call to action, or think it is somehow their problem they can’t place their order and so go away. However, if things overflow messily, you will tend to spot it. Or, at worse, someone using the site will spot it and let you know.

So this is why CSS overflows in a messy, visible way. By showing you the overflow, you are more likely to get a chance to fix it than if it hides the overflow. With the overflow property, however, you get a chance to make the decision yourself about what should happen. If you would prefer the overflow be cropped (which may be the right decision in some cases), use overflow: hidden.

Data Loss And Alignment

The better alignment abilities we have gained in recent years also have the potential for data loss. Consider a column of flex items that are up against the edge of the viewport and with different sizes. Aligned to flex-start, the items all stick out more to the right. Aligned to center, however, the longer item would actually end up off the side of the viewport. Alignment could therefore cause data loss.

To prevent accidental data loss caused by alignment, CSS now has some new keywords which can be used along with the alignment properties. These are specified in the Box Alignment specification — the specification which deals with alignment across all layout methods including Grid and Flexbox. They are currently only supported in Firefox. In our example above, if we set align-items: safe center, then the final item would become aligned to start rather than forcing the content to be centered. This would prevent the data loss caused by the item being centered and therefore pushed off the side of the viewport.

If you do want the alignment (even if it would cause overflow), then you can specify unsafe center. You’ve then requested that the browser does your chosen alignment no matter what then happens to the content. If you have Firefox, then you can see the two examples: one with safe and the second with unsafe alignment.

See the Pen [Safe and unsafe alignment](https://codepen.io/rachelandrew/pen/QWLMrpE) by Rachel Andrew.

See the Pen Safe and unsafe alignment by Rachel Andrew.

In the talk on which I based this article, I described web design as being a constant battle against overflow. One of the truths of designing for the web is that it’s very hard to know how tall or how large any element that contains text (in the block dimension) will be. However, as I have shown above, we have never had so many ways to manage overflow or the potential of overflow. This means that our designs can be far more resilient, and we can create patterns that will work with varying amounts of content. These might seem like small shifts in our capabilities, but I think the possibilities they open up to us are huge.

Smashing Editorial (il)