← Назад к вопросам

Как применить стиль ко всем элементам кроме последнего?

1.8 Middle🔥 194 комментариев
#JavaScript Core

Комментарии (4)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Применение стилей ко всем элементам кроме последнего

Это частая задача в вёрстке: например, добавить разделитель между элементами, но не после последнего. Есть несколько элегантных способов решить это на CSS и JavaScript.

1. CSS :not(:last-child) селектор

Самый простой и производительный способ — использовать :not(:last-child):

/* Применяем стиль ко всем, кроме последнего */
.list-item:not(:last-child) {
  border-bottom: 1px solid #e0e0e0;
  margin-bottom: 16px;
}

/* Альтернативно - с gap (рекомендуется для flexbox) */
.list {
  display: flex;
  flex-direction: column;
  gap: 16px; /* расстояние между элементами */
}

.list-item:not(:last-child) {
  border-bottom: 1px solid #e0e0e0;
}
<ul class="list">
  <li class="list-item">Элемент 1</li>
  <li class="list-item">Элемент 2</li>
  <li class="list-item">Элемент 3</li>
  <li class="list-item">Элемент 4</li>
</ul>

2. :not(:last-of-type) для более точной селекции

Если внутри есть разные типы элементов, используй :last-of-type:

/* Учитывает только элементы одного типа */
.card:not(:last-of-type) {
  margin-right: 16px;
  border-right: 1px solid #ddd;
}
<div class="grid">
  <div class="card">Card 1</div>
  <div class="card">Card 2</div>
  <div class="card">Card 3</div>
  <button>Action</button> <!-- не влияет на :last-of-type -->
</div>

3. :not(:last-child) с множественными селекторами (CSS Selectors Level 4)

Можно комбинировать :not() с несколькими условиями:

/* Стиль для всех элементов кроме последних двух */
.item:not(:last-child):not(:nth-last-child(2)) {
  border-bottom: 1px solid #ddd;
}

/* Стиль для всех кроме последнего и невидимых */
.item:not(:last-child):not(.hidden) {
  margin-bottom: 12px;
}

4. Классический способ с :last-child (старые браузеры)

Если нужна поддержка старых браузеров (IE11):

/* Применяем стиль всем */
.item {
  border-bottom: 1px solid #ddd;
  padding-bottom: 12px;
  margin-bottom: 12px;
}

/* Убираем у последнего */
.item:last-child {
  border-bottom: none;
  margin-bottom: 0;
  padding-bottom: 0;
}

5. Flexbox gap (современный подход для разделителей)

Если нужно просто расстояние между элементами, используй gap в flexbox/grid:

/* Контейнер с gap */
.list {
  display: flex;
  flex-direction: column;
  gap: 16px; /* автоматически между всеми, кроме... никого */
}

.list-item {
  /* border не нужен, gap уже создаёт расстояние */
}

/* Если всё же нужен разделитель между (не после последнего) */
.list-item:not(:last-child) {
  border-bottom: 1px solid #ddd;
  padding-bottom: 12px; /* расстояние до разделителя */
}

6. Tailwind CSS решение

В проекте PrepBro используем Tailwind, вот как там:

// JSX с Tailwind классами
import { cn } from '@/lib/utils';

function QuestionList({ questions }) {
  return (
    <div className="space-y-4"> {/* gap между элементами */}
      {questions.map((q, i) => (
        <div
          key={q.id}
          className={cn(
            'p-4 bg-surface-primary rounded-lg',
            i !== questions.length - 1 && 'border-b border-border-primary'
          )}
        >
          {q.title}
        </div>
      ))}
    </div>
  );
}

// Или используя встроенные Tailwind утилиты
function CommentList({ comments }) {
  return (
    <ul className="divide-y divide-border-primary">
      {comments.map(comment => (
        <li key={comment.id} className="py-4 px-0 first:pt-0 last:pb-0">
          {comment.text}
        </li>
      ))}
    </ul>
  );
}

7. JavaScript подход для динамических элементов

Если нужна логика на JavaScript (например, элементы добавляются динамически):

// Ручное применение класса
function applyStylesToAllButLast(containerSelector) {
  const container = document.querySelector(containerSelector);
  const items = container.querySelectorAll('.item');
  
  // Убираем класс у всех
  items.forEach(item => item.classList.remove('not-last'));
  
  // Добавляем всем кроме последнего
  const lastIndex = items.length - 1;
  items.forEach((item, index) => {
    if (index !== lastIndex) {
      item.classList.add('not-last');
    }
  });
}

// CSS класс
const style = document.createElement('style');
style.textContent = `
  .not-last {
    border-bottom: 1px solid #ddd;
    margin-bottom: 12px;
  }
`;
document.head.appendChild(style);

// Вызываем
applyStylesToAllButLast('.list');

// Если элементы добавляются динамически
const observer = new MutationObserver(() => {
  applyStylesToAllButLast('.list');
});

observer.observe(document.querySelector('.list'), {
  childList: true // следим за изменением списка
});

8. React hook для управления последним элементом

import { useRef, useEffect } from 'react';

function useIsLastElement(index, total) {
  return index === total - 1;
}

function ItemList({ items }) {
  return (
    <div className="space-y-4">
      {items.map((item, index) => {
        const isLast = useIsLastElement(index, items.length);
        
        return (
          <div
            key={item.id}
            className={cn(
              'p-4 bg-white rounded-lg',
              !isLast && 'border-b border-gray-200'
            )}
          >
            {item.content}
          </div>
        );
      })}
    </div>
  );
}

// Или компонент-враппер
function ItemWrapper({ children, isLast }) {
  return (
    <div className={!isLast ? 'border-b border-gray-200 pb-4' : ''}>
      {children}
    </div>
  );
}

function ItemList({ items }) {
  return (
    <div>
      {items.map((item, index) => (
        <ItemWrapper key={item.id} isLast={index === items.length - 1}>
          {item.content}
        </ItemWrapper>
      ))}
    </div>
  );
}

9. Практические примеры

// Пример 1: Список вопросов на PrepBro
function QuestionsList({ questions }) {
  return (
    <div className="space-y-3">
      {questions.map((q) => (
        <div
          key={q.id}
          className="p-4 bg-surface-secondary rounded-lg hover:bg-surface-tertiary transition-colors not-last:border-b not-last:border-border-primary"
        >
          <h3 className="text-content-primary font-medium">{q.title}</h3>
          <p className="text-content-secondary text-sm mt-1">{q.text}</p>
        </div>
      ))}
    </div>
  );
}

// Пример 2: Комментарии с разделителями
function CommentsList({ comments }) {
  return (
    <ul className="divide-y divide-border-primary">
      {comments.map((comment) => (
        <li key={comment.id} className="py-4 px-0">
          <div className="flex gap-3">
            <img src={comment.avatar} className="w-8 h-8 rounded-full" />
            <div>
              <p className="font-medium text-content-primary">{comment.author}</p>
              <p className="text-content-secondary text-sm">{comment.text}</p>
            </div>
          </div>
        </li>
      ))}
    </ul>
  );
}

// Пример 3: Горизонтальная лента элементов
function HorizontalScroll({ items }) {
  return (
    <div className="flex overflow-x-auto gap-4">
      {items.map((item, index) => (
        <div
          key={item.id}
          className={cn(
            'flex-shrink-0 w-64 p-4 bg-surface-primary rounded-lg',
            index !== items.length - 1 && 'border-r border-border-primary pr-6'
          )}
        >
          {item.name}
        </div>
      ))}
    </div>
  );
}

Итоговая таблица методов

МетодБраузерыИспользованиеСложность
:not(:last-child)>=IE9Статические спискиНизкая
:not(:last-of-type)>=IE9Смешанные типыНизкая
gap в flexboxВсе модерныеПросто расстояниеНизкая
divide-y TailwindВсе модерныеРазделители в TailwindНизкая
JavaScript classListВсеДинамические элементыСредняя
React условная логикаВсеReact компонентыСредняя

Best Practice для PrepBro

Используй CSS селекторы :not(:last-child) — это стандарт, понятный для чтения, без лишнего JS. Только если элементы добавляются динамически очень часто, переходи на JavaScript решение.

Как применить стиль ко всем элементам кроме последнего? | PrepBro