For AI agents: the complete documentation index is available at https://nhanbe.id.vn/llms.txt, the full documentation bundle is available at https://nhanbe.id.vn/llms-full.txt, and this page is available as Markdown at https://nhanbe.id.vn/frontend/scss/aem-clientlib-scss.md.

Configuring SCSS compilation and Client Library organization in AEM frontend build.

SCSS trong AEM Clientlib

Tổ chức và build SCSS trong dự án AEM, gắn style vào component theo BEM, và load qua clientlib.

Luồng build

SCSS viết trong ui.frontend, Webpack compile ra CSS, plugin (vd aem-clientlib-generator) copy vào clientlib trong ui.apps. AEM serve CSS qua clientlib category.

Cấu trúc thư mục

ui.frontend/src/main/webpack/
├── site/
│   ├── main.scss              # entry
│   └── styles/
│       ├── abstracts/         # _variables, _mixins, _breakpoints
│       ├── base/              # _reset, _typography
│       ├── components/        # _hero.scss, _card.scss (mỗi AEM component)
│       └── layout/            # _grid, _header, _footer
// main.scss
@use 'styles/abstracts/variables';
@use 'styles/abstracts/mixins';
@use 'styles/base/reset';
@use 'styles/components/hero';
@use 'styles/components/card';

BEM gắn với AEM component

AEM component nên có một class gốc theo tên component, style scope trong class đó để không rò rỉ sang component khác. Quy ước BEM: Block là component, Element là phần con, Modifier là biến thể.

// _hero.scss
.cmp-hero {
  padding: 32px;

  &__title {
    font-size: 2rem;
  }

  &__image {
    width: 100%;
  }

  &--centered {
    text-align: center;
  }
}

HTL render class khớp:

<div class="cmp-hero cmp-hero--centered">
  <h1 class="cmp-hero__title">${model.title}</h1>
  <img class="cmp-hero__image" src="${model.imageSrc @ context='uri'}"/>
</div>

Tiền tố cmp- (theo Core Components) giúp tránh trùng class với thư viện ngoài.

Responsive với breakpoint thống nhất

Đặt breakpoint vào map dùng chung, mixin respond() cho mọi component. Tránh viết media query rời rạc với giá trị khác nhau.

// abstracts/_breakpoints.scss
$breakpoints: (
  'sm': 576px,
  'md': 768px,
  'lg': 992px,
  'xl': 1200px
);

@mixin respond($name) {
  @media (min-width: map-get($breakpoints, $name)) {
    @content;
  }
}
.cmp-hero {
  padding: 16px;

  @include respond('md') {
    padding: 32px;
  }

  @include respond('lg') {
    padding: 48px;
  }
}

Style cho Vue component trong AEM

Khi component là Vue SFC, có thể đặt style trong <style> của SFC hoặc trong SCSS chung. Lưu ý:

  • <style scoped> trong SFC giới hạn style trong component đó bằng data attribute. Tốt cho cô lập nhưng tách rời khỏi clientlib chung.
  • Để dùng biến/mixin chung trong SFC, import partial vào block style.
<style lang="scss" scoped>
@use '@/styles/abstracts/variables' as v;

.product-card {
  border: 1px solid v.$muted;
}
</style>

Tránh xung đột style

  • Luôn scope style trong class gốc component, không viết selector trần (h2 {}, .title {}) ở cấp global.
  • Không lồng selector quá sâu, giữ specificity thấp để author dễ override qua style system của AEM nếu cần.
  • Author có thể bật nhiều instance cùng component trên một trang, style phải hoạt động độc lập, không dựa vào vị trí DOM tuyệt đối.

Tích hợp Style System của AEM

AEM Style System cho phép author chọn class CSS định nghĩa sẵn cho component qua policy. Khai báo các class style (vd cmp-hero--centered, cmp-hero--dark) trong SCSS, rồi map vào policy trong _cq_design_dialog hoặc template policy để author bật/tắt.

Tips

ViệcKhuyến nghị
Biến chungabstracts/_variables.scss, nạp đầu tiên
Đặt tên classBEM, tiền tố theo component
BreakpointMap dùng chung + mixin respond()
ScopeStyle trong class gốc component
ModifierKhai báo class, map vào Style System policy