Back

Creating a Minimal Outline Button with Hover Fill Effect

Learn how to design a sleek, minimal outline button that fills with color on hover for a clean and modern user interface.

HTML

The HTML structure for our outline button is very simple - just a container div and a button element with the class outline-button.

        <div class="button-container">
          <button class="outline-button">Learn More</button>
        </div>
      
The button text can be customized to match your specific call-to-action.

CSS

First, we set up the container to center our button:

        .button-container {
          display: flex;
          justify-content: center;
          align-items: center;
        }
      
Next, we define the outline button with CSS variables for easy customization:

        .outline-button {
          --button-color: #3B82F6;
          --button-hover-color: #2563EB;
          --button-text-hover: white;
          --button-padding-x: 24px;
          --button-padding-y: 12px;
          --button-font-size: 16px;
          --button-radius: 6px;
          --button-border-width: 2px;
          --button-transition-time: 0.3s;
          
          font-family: system-ui, -apple-system, sans-serif;
          font-weight: 500;
          font-size: var(--button-font-size);
          color: var(--button-color);
          background-color: transparent;
          border: var(--button-border-width) solid var(--button-color);
          border-radius: var(--button-radius);
          padding: var(--button-padding-y) var(--button-padding-x);
          cursor: pointer;
          position: relative;
          overflow: hidden;
          z-index: 1;
          transition: color var(--button-transition-time) ease;
        }
      
The key properties here: - We define a transparent background with a colored border for the outline look - We set position: relative and z-index: 1 to prepare for our fill effect - overflow: hidden ensures our fill animation stays within the button borders - We only transition the text color, as the background will be handled by a pseudo-element To create the fill effect on hover, we use a pseudo-element:

        .outline-button::before {
          content: '';
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background-color: var(--button-color);
          transform: translateY(100%);
          transition: transform var(--button-transition-time) ease;
          z-index: -1;
        }

        .outline-button:hover {
          color: var(--button-text-hover);
        }

        .outline-button:hover::before {
          transform: translateY(0);
        }
      
This technique creates a smooth fill animation from bottom to top when hovering. The pseudo-element starts below the button (translateY(100%)) and moves up to fill it. We also add an active state for better interaction feedback:

        .outline-button:active {
          transform: scale(0.98);
        }
      
The active state slightly reduces the button size to create a subtle 'press' effect. For accessibility, we add a focus state:

        /* Focus state for accessibility */
        .outline-button:focus-visible {
          outline: 2px solid rgba(59, 130, 246, 0.5);
          outline-offset: 2px;
        }
      
Finally, we provide alternative color schemes and animation variations:

        /* Alternative color schemes */
        .outline-button.danger {
          --button-color: #EF4444;
          --button-hover-color: #DC2626;
        }

        .outline-button.success {
          --button-color: #10B981;
          --button-hover-color: #059669;
        }

        .outline-button.warning {
          --button-color: #F59E0B;
          --button-hover-color: #D97706;
        }

        /* Alternative fill animations */
        .outline-button.slide-right::before {
          transform: translateX(-100%);
          width: 100%;
          height: 100%;
        }

        .outline-button.slide-right:hover::before {
          transform: translateX(0);
        }

        .outline-button.slide-center::before {
          transform: translateX(-50%) scaleX(0);
          width: 100%;
          height: 100%;
        }

        .outline-button.slide-center:hover::before {
          transform: translateX(-50%) scaleX(1);
        }
      
The different animation classes provide alternative ways for the background to fill in, giving you multiple options for your interface: - The default slides up from the bottom - slide-right slides in from the left - slide-center expands from the center outward This outline button offers several advantages: - Visual lightness: The minimal design works well in clean, modern interfaces. - Clear interaction: The fill effect provides satisfying visual feedback on hover. - Versatile styling: Works well for secondary actions alongside more prominent primary buttons. - Animation options: Different fill animations add visual interest and can match the mood of your site. - Accessible design: High contrast between the outline and fill states, with proper focus styling. This button style is perfect for secondary actions, "learn more" links, or in interfaces where you want a more subtle button style that still provides clear interactive feedback.

Whole code

<div class="button-container">
  <button class="outline-button">Learn More</button>
</div>

<style>
.button-container {
  display: flex;
  justify-content: center;
  align-items: center;
}

.outline-button {
  --button-color: #3B82F6;
  --button-hover-color: #2563EB;
  --button-text-hover: white;
  --button-padding-x: 24px;
  --button-padding-y: 12px;
  --button-font-size: 16px;
  --button-radius: 6px;
  --button-border-width: 2px;
  --button-transition-time: 0.3s;
  
  font-family: system-ui, -apple-system, sans-serif;
  font-weight: 500;
  font-size: var(--button-font-size);
  color: var(--button-color);
  background-color: transparent;
  border: var(--button-border-width) solid var(--button-color);
  border-radius: var(--button-radius);
  padding: var(--button-padding-y) var(--button-padding-x);
  cursor: pointer;
  position: relative;
  overflow: hidden;
  z-index: 1;
  transition: color var(--button-transition-time) ease;
}

.outline-button::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: var(--button-color);
  transform: translateY(100%);
  transition: transform var(--button-transition-time) ease;
  z-index: -1;
}

.outline-button:hover {
  color: var(--button-text-hover);
}

.outline-button:hover::before {
  transform: translateY(0);
}

.outline-button:active {
  transform: scale(0.98);
}

/* Focus state for accessibility */
.outline-button:focus-visible {
  outline: 2px solid rgba(59, 130, 246, 0.5);
  outline-offset: 2px;
}

/* Alternative color schemes */
.outline-button.danger {
  --button-color: #EF4444;
  --button-hover-color: #DC2626;
}

.outline-button.success {
  --button-color: #10B981;
  --button-hover-color: #059669;
}

.outline-button.warning {
  --button-color: #F59E0B;
  --button-hover-color: #D97706;
}

/* Alternative fill animations */
.outline-button.slide-right::before {
  transform: translateX(-100%);
  width: 100%;
  height: 100%;
}

.outline-button.slide-right:hover::before {
  transform: translateX(0);
}

.outline-button.slide-center::before {
  transform: translateX(-50%) scaleX(0);
  width: 100%;
  height: 100%;
}

.outline-button.slide-center:hover::before {
  transform: translateX(-50%) scaleX(1);
}
</style>
      
Thank you for reading this article.

Comments

More buttons

Similar

See also