Vishwa Fernando took his first five-wicket haul in Tests as Sri Lanka fought back on the second day of the second and final Test against South Africa at the Wanderers Stadium in Johannesburg on Monday.
But the tourists were still in deep trouble, losing first innings top-scorer Kusal Perera in the third over of their second innings.
Sri Lanka were 16 for one at tea, a deficit of 129 runs.
The left-armed Vishwa took five for 101 as South Africa were bowled out for 302, a first innings lead of 145 runs, despite reaching 218 for one. Namesake and debutant Asitha Fernando and medium-pacer Dasun Shanaka took two wickets each.
South Africa lost their last nine wickets for 84 runs after Shanaka dismissed Dean Elgar for 127, breaking a second-wicket stand of 184 between Elgar and Rassie van der Dussen (67).
South Africa's collapse seemed an unlikely scenario when Elgar and Van der Dussen scored 68 runs off 14 overs in the first hour of the day. But the mid-morning drinks break brought a change in fortunes, with both batsmen dismissed in the first two overs after drinks.
Elgar, who made 95 in South Africa's innings win in the first Test at Centurion, completed his 13th Test century after starting the day on 92. He hit 22 fours in a 163-ball innings.
Perera, who made 64 and 60 in his previous two innings, was bowled for one by a ball from Lungi Ngidi which swung in from around the wicket.