FadeScroll#
FadeScroll 은 스크롤 가능한 [child] 를 감싸고 그 가장자리에 그라디언트 페이드 마스크를 씌워 "더 많은 콘텐츠가 보이지 않는 영역에 있음" 을 시각적으로 암시합니다.
Live Preview#
default
Web
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12
Item 13
Item 14
Item 15
Item 16
Item 17
Item 18
Item 19
Item 20
Flutter
Loading Flutter...
class FadeScrollDefaultExample extends StatelessComponent {
const FadeScrollDefaultExample({super.key});
@override
Component build(BuildContext context) {
return div(
[
CoFadeScroll(
child: div([
for (var i = 0; i < 20; i += 1)
div(
[Text('Item ${i + 1}').bodyMedium.onSurface],
classes: 'py-2 px-4',
),
]),
),
],
styles: Styles(raw: {'height': '200px'}),
);
}
}
class FadeScrollDefaultExample extends StatelessWidget {
const FadeScrollDefaultExample({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 200,
child: CoFadeScroll(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (var i = 0; i < 20; i += 1)
Padding(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Text('Item ${i + 1}').bodyMedium.onSurface,
),
],
),
),
);
}
}
horizontal
Web
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12
Item 13
Item 14
Item 15
Item 16
Item 17
Item 18
Item 19
Item 20
Flutter
Loading Flutter...
class FadeScrollHorizontalExample extends StatelessComponent {
const FadeScrollHorizontalExample({super.key});
@override
Component build(BuildContext context) {
return CoFadeScroll(
direction: .horizontal,
showScrollbar: true,
child: div(
[
for (var i = 0; i < 20; i += 1)
div(
[Text('Item ${i + 1}').bodyMedium.onSurface],
classes: 'flex items-center px-3 whitespace-nowrap',
),
],
classes: 'flex',
styles: Styles(raw: {'width': 'max-content'}),
),
);
}
}
class FadeScrollHorizontalExample extends StatelessWidget {
const FadeScrollHorizontalExample({super.key});
@override
Widget build(BuildContext context) {
return CoFadeScroll(
direction: .horizontal,
showScrollbar: true,
child: Row(
children: [
for (var i = 0; i < 20; i += 1)
Padding(
padding: EdgeInsets.symmetric(horizontal: 12),
child: Center(
child: Text('Item ${i + 1}').bodyMedium.onSurface,
),
),
],
),
);
}
}
with-scrollbar
Web
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12
Item 13
Item 14
Item 15
Item 16
Item 17
Item 18
Item 19
Item 20
Flutter
Loading Flutter...
class FadeScrollWithScrollbarExample extends StatelessComponent {
const FadeScrollWithScrollbarExample({super.key});
@override
Component build(BuildContext context) {
return div(
[
CoFadeScroll(
showScrollbar: true,
child: div([
for (var i = 0; i < 20; i += 1)
div(
[Text('Item ${i + 1}').bodyMedium.onSurface],
classes: 'py-2 px-4',
),
]),
),
],
styles: Styles(raw: {'height': '200px'}),
);
}
}
class FadeScrollWithScrollbarExample extends StatelessWidget {
const FadeScrollWithScrollbarExample({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 200,
child: CoFadeScroll(
showScrollbar: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (var i = 0; i < 20; i += 1)
Padding(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Text('Item ${i + 1}').bodyMedium.onSurface,
),
],
),
),
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 가로 스크롤 카드 리스트의 좌/우 끝에 콘텐츠가 부드럽게 사라지게 표현할 때
- 세로 스크롤 컨테이너 위/아래에 페이드 그라디언트로 추가 콘텐츠 존재를 암시할 때
- 모달/드로어 내부의 긴 콘텐츠가 보더 영역까지 닿을 때 부드러운 시각 전환
대신 다른 컴포넌트를 사용하세요:
OverflowMarquee: 텍스트가 컨테이너 너비를 넘을 때 자동 스크롤되는 효과가 필요할 때ScrollableClient: 양 끝 그라디언트가 필요 없는 단순 스크롤 영역
기본 사용법 (Basic Usage)#
final controller = ScrollController();
CoFadeScroll(
controller: controller,
child: ListView(
controller: controller,
children: items,
),
)
// 가로 스크롤 + 양 끝 페이드 32px
CoFadeScroll(
controller: controller,
direction: CoreFadeScrollDirection.horizontal,
startOffset: 32,
endOffset: 32,
child: ListView(
controller: controller,
scrollDirection: Axis.horizontal,
children: cards,
),
)
// 기본 — 세로 스크롤 + 양 끝 페이드 (40px default)
CoFadeScroll(
child: div([for (final item in items) ...]),
)
// 가로 스크롤 + 양 끝 페이드 32px
CoFadeScroll(
direction: CoreFadeScrollDirection.horizontal,
startOffset: 32,
endOffset: 32,
child: div(
[for (final c in cards) ...],
styles: Styles(raw: {'display': 'flex'}),
),
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
child |
Widget (Flutter) / Component (Web) |
필수 | 스크롤 가능한 콘텐츠 |
direction |
CoreFadeScrollDirection |
vertical |
스크롤 축 (vertical / horizontal) |
startOffset |
double? |
null (theme 또는 0) |
시작 가장자리 페이드 영역 (px) |
endOffset |
double? |
null (theme 또는 0) |
끝 가장자리 페이드 영역 (px) |
gradient |
List<Color>? (Flutter) / List<String>? (Web) |
[opaque, transparent] |
페이드 색상 stops |
controller |
ScrollController? |
필수 (Flutter) / N/A (Web) | Flutter 스크롤 컨트롤러. Web 은 native scroll 사용 |
동작 스펙 (Behavior)#
-
Flutter:
ListenableBuilder가controller위치를 listen → 스크롤 끝 도달 시 그쪽 페이드 자동 제거 (dynamic). - Web (현재): SSR-safe
mask-image정적 그라디언트. 양 끝 페이드 항상 적용. -
Web (후속):
onScrollmeasurer 추가 → CSS variable (--co-fade-start-alpha/--co-fade-end-alpha) 동적 업데이트로 Flutter 와 동일한 dynamic 동작.
크로스 플랫폼 차이점 (Platform Differences)#
| 항목 | Flutter | Web |
|---|---|---|
| 클래스명 | CoFadeScroll | CoFadeScroll |
| 페이드 메커니즘 | ShaderMask + LinearGradient |
CSS mask-image: linear-gradient(...) |
| 스크롤 컨트롤 | ScrollController (필수) |
native <div> scroll |
| Dynamic 페이드 | ✅ 끝 도달 시 그쪽 fade 제거 | ⚠ 정적 (후속 step 에서 dynamic) |
관련 컴포넌트 (Related Components)#
- OverflowMarquee: 텍스트 자동 스크롤 + 양 끝 fade.
- ScrollableClient: fade 없는 단순 스크롤.